diff --git a/converter/src/main/java/lcsb/mapviewer/converter/ComplexZipConverter.java b/converter/src/main/java/lcsb/mapviewer/converter/ComplexZipConverter.java
index dc91e510ca4d12a82a54da6a2767154608083e17..e2640f0b3ecfafcf9d143f661a8d4dd6807b37c1 100644
--- a/converter/src/main/java/lcsb/mapviewer/converter/ComplexZipConverter.java
+++ b/converter/src/main/java/lcsb/mapviewer/converter/ComplexZipConverter.java
@@ -52,355 +52,365 @@ import lcsb.mapviewer.model.map.species.Species;
  */
 public class ComplexZipConverter {
 
-	/**
-	 * Size of the buffer used for accessing single chunk of data from input
-	 * stream.
-	 */
-	private static final int						BUFFER_SIZE	= 1024;
+  /**
+   * Size of the buffer used for accessing single chunk of data from input stream.
+   */
+  private static final int BUFFER_SIZE = 1024;
 
-	/**
-	 * Default class logger.
-	 */
-	private static Logger								logger			= Logger.getLogger(ComplexZipConverter.class);
+  /**
+   * Default class logger.
+   */
+  private static Logger logger = Logger.getLogger(ComplexZipConverter.class);
 
-	/**
-	 * Class used to create single submap from a file.
-	 */
-	private Class<? extends IConverter>	converterClazz;
+  /**
+   * Class used to create single submap from a file.
+   */
+  private Class<? extends IConverter> converterClazz;
 
-	/**
-	 * Default constructor. Checks if the class given in the parameter is proper
-	 * {@link IConverter} implementation.
-	 * 
-	 * @param clazz
-	 *          {@link IConverter} class used for creation of the single submap
-	 */
-	public ComplexZipConverter(Class<? extends IConverter> clazz) {
-		if (Modifier.isAbstract(clazz.getModifiers())) {
-			throw new InvalidClassException("Param class cannot be abstract");
-		}
+  /**
+   * Default constructor. Checks if the class given in the parameter is proper
+   * {@link IConverter} implementation.
+   * 
+   * @param clazz
+   *          {@link IConverter} class used for creation of the single submap
+   */
+  public ComplexZipConverter(Class<? extends IConverter> clazz) {
+    if (Modifier.isAbstract(clazz.getModifiers())) {
+      throw new InvalidClassException("Param class cannot be abstract");
+    }
 
-		if (Modifier.isInterface(clazz.getModifiers())) {
-			throw new InvalidClassException("Param class cannot be an interface");
-		}
+    if (Modifier.isInterface(clazz.getModifiers())) {
+      throw new InvalidClassException("Param class cannot be an interface");
+    }
 
-		converterClazz = clazz;
-	}
+    converterClazz = clazz;
+  }
 
-	/**
-	 * Creates complex {@link Model} that contains submaps.
-	 * 
-	 * @param params
-	 *          {@link ComplexZipConverterParams object} with information about
-	 *          data from which result is going to be created
-	 * @return complex {@link Model} created from input data
-	 * @throws InvalidInputDataExecption
-	 *           thrown when there is a problem with accessing input data
-	 */
-	public Model createModel(ComplexZipConverterParams params) throws InvalidInputDataExecption {
-		try {
-			ZipFile zipFile = params.getZipFile();
-			Enumeration<? extends ZipEntry> entries;
-			String mapping = validateSubmodelInformation(params, zipFile);
+  /**
+   * Creates complex {@link Model} that contains submaps.
+   * 
+   * @param params
+   *          {@link ComplexZipConverterParams object} with information about data
+   *          from which result is going to be created
+   * @return complex {@link Model} created from input data
+   * @throws InvalidInputDataExecption
+   *           thrown when there is a problem with accessing input data
+   */
+  public Model createModel(ComplexZipConverterParams params) throws InvalidInputDataExecption {
+    try {
+      ZipFile zipFile = params.getZipFile();
+      Enumeration<? extends ZipEntry> entries;
+      String mapping = validateSubmodelInformation(params, zipFile);
 
-			IConverter converter = createConverterInstance();
-			Map<String, Model> filenameModelMap = new HashMap<String, Model>();
-			Map<String, Model> nameModelMap = new HashMap<String, Model>();
+      IConverter converter = createConverterInstance();
+      Map<String, Model> filenameModelMap = new HashMap<String, Model>();
+      Map<String, Model> nameModelMap = new HashMap<String, Model>();
 
-			entries = zipFile.entries();
-			Model result = null;
-			List<Layout> layouts = new ArrayList<Layout>();
-			List<DataMiningSet> dataMiningSets = new ArrayList<>();
-			while (entries.hasMoreElements()) {
-				ZipEntry entry = entries.nextElement();
-				if (!entry.isDirectory()) {
-					ZipEntryFile zef = params.getEntry(entry.getName());
-					if (zef instanceof ModelZipEntryFile) {
-						ModelZipEntryFile modelEntryFile = (ModelZipEntryFile) zef;
-						InputStream is = zipFile.getInputStream(entry);
-						ConverterParams cParams = new ConverterParams();
-						cParams.inputStream(is);
-						Model model = converter.createModel(cParams);
-						model.setName(modelEntryFile.getName());
-						filenameModelMap.put(entry.getName(), model);
-						nameModelMap.put(FilenameUtils.getBaseName(modelEntryFile.getFilename()), model);
-						if (modelEntryFile.isRoot()) {
-							result = model;
-						}
-					} else if (zef instanceof LayoutZipEntryFile) {
-						layouts.add(layoutZipEntryFileToLayout(params, zipFile, entry, (LayoutZipEntryFile) zef));
-					} else if (zef instanceof ImageZipEntryFile) {
-						continue;
-						// imageEntries.add((ImageZipEntryFile) zef);
-					} else if (zef instanceof DataMiningZipEntryFile) {
-						dataMiningSets.add(dataMiningZipEntryToDataMiningSet(zipFile, entry, (DataMiningZipEntryFile) zef));
-					} else {
-						throw new NotImplementedException("Unknwon entry type: " + zef.getClass());
-					}
-				}
-			}
+      entries = zipFile.entries();
+      Model result = null;
+      List<Layout> layouts = new ArrayList<Layout>();
+      List<DataMiningSet> dataMiningSets = new ArrayList<>();
+      while (entries.hasMoreElements()) {
+        ZipEntry entry = entries.nextElement();
+        if (!entry.isDirectory()) {
+          ZipEntryFile zef = params.getEntry(entry.getName());
+          if (zef instanceof ModelZipEntryFile) {
+            ModelZipEntryFile modelEntryFile = (ModelZipEntryFile) zef;
+            InputStream is = zipFile.getInputStream(entry);
+            ConverterParams cParams = new ConverterParams();
+            cParams.inputStream(is);
+            Model model = converter.createModel(cParams);
+            model.setName(modelEntryFile.getName());
+            filenameModelMap.put(entry.getName(), model);
+            nameModelMap.put(FilenameUtils.getBaseName(modelEntryFile.getFilename()), model);
+            if (modelEntryFile.isRoot()) {
+              result = model;
+            }
+          } else if (zef instanceof LayoutZipEntryFile) {
+            layouts.add(layoutZipEntryFileToLayout(params, zipFile, entry, (LayoutZipEntryFile) zef));
+          } else if (zef instanceof ImageZipEntryFile) {
+            continue;
+            // imageEntries.add((ImageZipEntryFile) zef);
+          } else if (zef instanceof DataMiningZipEntryFile) {
+            dataMiningSets.add(dataMiningZipEntryToDataMiningSet(zipFile, entry, (DataMiningZipEntryFile) zef));
+          } else {
+            throw new NotImplementedException("Unknwon entry type: " + zef.getClass());
+          }
+        }
+      }
 
-			result.addDataMiningSets(dataMiningSets);
+      result.addDataMiningSets(dataMiningSets);
 
-			for (Entry<String, Model> entry : filenameModelMap.entrySet()) {
-				String filename = entry.getKey();
-				Model model = entry.getValue();
-				ZipEntryFile zef = params.getEntry(filename);
-				if (zef instanceof ModelZipEntryFile) {
-					ModelZipEntryFile modelEntryFile = (ModelZipEntryFile) zef;
-					if (!modelEntryFile.isRoot() && !modelEntryFile.isMappingFile()) {
-						ModelSubmodelConnection submodel = new ModelSubmodelConnection(model, modelEntryFile.getType());
-						submodel.setName(modelEntryFile.getName());
-						result.addSubmodelConnection(submodel);
-					}
-				}
-			}
-			for (Layout layout : layouts) {
-				Layout topLayout = new Layout(layout);
-				result.addLayout(topLayout);
-				int modelId = 0;
-				topLayout.setDirectory(topLayout.getDirectory() + modelId);
-				modelId++;
-				for (ModelSubmodelConnection connection : result.getSubmodelConnections()) {
-					Layout childLayout = new Layout(layout);
-					// we need to set separate directory names for different submodels
-					childLayout.setDirectory(childLayout.getDirectory() + modelId);
-					modelId++;
-					childLayout.setParentLayout(topLayout);
-					connection.getSubmodel().addLayout(childLayout);
-				}
-			}
-			Model mappingModel = filenameModelMap.get(mapping);
-			if (mappingModel != null) {
-				for (Reaction reaction : mappingModel.getReactions()) {
-					processReaction(mapping, nameModelMap, result, reaction);
-				}
-			}
-			return result;
-		} catch (IOException e) {
-			throw new InvalidArgumentException(e);
-		}
-	}
+      for (Entry<String, Model> entry : filenameModelMap.entrySet()) {
+        String filename = entry.getKey();
+        Model model = entry.getValue();
+        ZipEntryFile zef = params.getEntry(filename);
+        if (zef instanceof ModelZipEntryFile) {
+          ModelZipEntryFile modelEntryFile = (ModelZipEntryFile) zef;
+          if (!modelEntryFile.isRoot() && !modelEntryFile.isMappingFile()) {
+            ModelSubmodelConnection submodel = new ModelSubmodelConnection(model, modelEntryFile.getType());
+            submodel.setName(modelEntryFile.getName());
+            result.addSubmodelConnection(submodel);
+          }
+        }
+      }
+      for (Layout layout : layouts) {
+        Layout topLayout = new Layout(layout);
+        result.addLayout(topLayout);
+        int modelId = 0;
+        topLayout.setDirectory(topLayout.getDirectory() + modelId);
+        modelId++;
+        for (ModelSubmodelConnection connection : result.getSubmodelConnections()) {
+          Layout childLayout = new Layout(layout);
+          // we need to set separate directory names for different submodels
+          childLayout.setDirectory(childLayout.getDirectory() + modelId);
+          modelId++;
+          childLayout.setParentLayout(topLayout);
+          connection.getSubmodel().addLayout(childLayout);
+        }
+      }
+      Model mappingModel = filenameModelMap.get(mapping);
+      if (mappingModel != null) {
+        for (Reaction reaction : mappingModel.getReactions()) {
+          processReaction(mapping, nameModelMap, result, reaction);
+        }
+      }
+      return result;
+    } catch (IOException e) {
+      throw new InvalidArgumentException(e);
+    }
+  }
 
-	/**
-	 * Process a single reaction in mapping file (transfomring reaction into
-	 * connection between submodels).
-	 * 
-	 * @param mapping
-	 *          name of the mapping file
-	 * @param nameModelMap
-	 *          mapping between file names and models
-	 * @param topModel
-	 *          top model
-	 * @param reaction
-	 *          reaction to transform into connection
-	 */
-	public void processReaction(String mapping, Map<String, Model> nameModelMap, Model topModel, Reaction reaction) {
-		if (reaction.getReactants().size() > 1) {
-			logger.warn("[SUBMODEL MAPPING] Reaction " + reaction.getIdReaction() + " in mapping file (" + mapping + ") contains too many reactants. Skipped");
-		} else if (reaction.getProducts().size() > 1) {
-			logger.warn("[SUBMODEL MAPPING] Reaction " + reaction.getIdReaction() + " in mapping file (" + mapping + ") contains too many products. Skipped");
-		} else if (reaction.getModifiers().size() > 0) {
-			logger.warn("[SUBMODEL MAPPING] Reaction " + reaction.getIdReaction() + " in mapping file (" + mapping + ") contains modifiers. Skipped");
-		} else {
-			Element fromAlias = reaction.getReactants().get(0).getElement();
-			Element toAlias = reaction.getProducts().get(0).getElement();
-			if (!(fromAlias instanceof Species)) {
-				logger
-						.warn("[SUBMODEL MAPPING] Reaction " + reaction.getIdReaction() + " in mapping file (" + mapping + ") contains doesn't start in species. Skipped");
-			} else if (!(toAlias instanceof Species)) {
-				logger.warn("[SUBMODEL MAPPING] Reaction " + reaction.getIdReaction() + " in mapping file (" + mapping + ") contains doesn't end in species. Skipped");
-			} else {
-				Complex complexFrom = ((Species) fromAlias).getComplex();
-				Complex complexTo = ((Species) toAlias).getComplex();
-				if (complexFrom == null) {
-					logger.warn(
-							"[SUBMODEL MAPPING] Reaction " + reaction.getIdReaction() + " in mapping file (" + mapping + ") contains doesn't start inside complex. Skipped");
-				} else if (complexTo == null && (!(toAlias instanceof Complex))) {
-					logger.warn(
-							"[SUBMODEL MAPPING] Reaction " + reaction.getIdReaction() + " in mapping file (" + mapping + ") contains doesn't end inside complex. Skipped");
-				} else {
-					if (complexTo == null) {
-						complexTo = (Complex) toAlias;
-					}
-					String fromName = complexFrom.getName();
-					String toName = complexTo.getName();
-					Model fromModel = nameModelMap.get(fromName);
-					Model toModel = nameModelMap.get(toName);
-					if (fromModel == null) {
-						throw new InvalidArgumentException("Mapping file references to " + fromName + " submodel. But such model doesn't exist");
-					} else if (toModel == null) {
-						throw new InvalidArgumentException("Mapping file references to " + toName + " submodel. But such model doesn't exist");
-					}
-					Element source = fromModel.getElementByElementId(fromAlias.getName());
-					if (source == null) {
-						throw new InvalidArgumentException("Mapping file references to element with alias: " + fromAlias.getName() + ". But such element doesn't exist");
-					}
-					Element dest = null;
-					if (!(toAlias instanceof Complex)) {
-						dest = fromModel.getElementByElementId(toAlias.getName());
-					}
-					SubmodelType type = SubmodelType.UNKNOWN;
-					if (fromAlias instanceof Protein) {
-						type = SubmodelType.DOWNSTREAM_TARGETS;
-					} else if (fromAlias instanceof Phenotype) {
-						type = SubmodelType.PATHWAY;
-					}
-					ElementSubmodelConnection connection = new ElementSubmodelConnection(toModel, type);
-					connection.setFromElement(source);
-					connection.setToElement(dest);
-					connection.setName(toModel.getName());
-					source.setSubmodel(connection);
-				}
-			}
-		}
-	}
+  /**
+   * Process a single reaction in mapping file (transfomring reaction into
+   * connection between submodels).
+   * 
+   * @param mapping
+   *          name of the mapping file
+   * @param nameModelMap
+   *          mapping between file names and models
+   * @param topModel
+   *          top model
+   * @param reaction
+   *          reaction to transform into connection
+   */
+  public void processReaction(String mapping, Map<String, Model> nameModelMap, Model topModel, Reaction reaction) {
+    if (reaction.getReactants().size() > 1) {
+      logger.warn("[SUBMODEL MAPPING] Reaction " + reaction.getIdReaction() + " in mapping file (" + mapping
+          + ") contains too many reactants. Skipped");
+    } else if (reaction.getProducts().size() > 1) {
+      logger.warn("[SUBMODEL MAPPING] Reaction " + reaction.getIdReaction() + " in mapping file (" + mapping
+          + ") contains too many products. Skipped");
+    } else if (reaction.getModifiers().size() > 0) {
+      logger.warn("[SUBMODEL MAPPING] Reaction " + reaction.getIdReaction() + " in mapping file (" + mapping
+          + ") contains modifiers. Skipped");
+    } else {
+      Element fromAlias = reaction.getReactants().get(0).getElement();
+      Element toAlias = reaction.getProducts().get(0).getElement();
+      if (!(fromAlias instanceof Species)) {
+        logger.warn("[SUBMODEL MAPPING] Reaction " + reaction.getIdReaction() + " in mapping file (" + mapping
+            + ") contains doesn't start in species. Skipped");
+      } else if (!(toAlias instanceof Species)) {
+        logger.warn("[SUBMODEL MAPPING] Reaction " + reaction.getIdReaction() + " in mapping file (" + mapping
+            + ") contains doesn't end in species. Skipped");
+      } else {
+        Complex complexFrom = ((Species) fromAlias).getComplex();
+        Complex complexTo = ((Species) toAlias).getComplex();
+        if (complexFrom == null) {
+          logger.warn("[SUBMODEL MAPPING] Reaction " + reaction.getIdReaction() + " in mapping file (" + mapping
+              + ") contains doesn't start inside complex. Skipped");
+        } else if (complexTo == null && (!(toAlias instanceof Complex))) {
+          logger.warn("[SUBMODEL MAPPING] Reaction " + reaction.getIdReaction() + " in mapping file (" + mapping
+              + ") contains doesn't end inside complex. Skipped");
+        } else {
+          if (complexTo == null) {
+            complexTo = (Complex) toAlias;
+          }
+          String fromName = complexFrom.getName();
+          String toName = complexTo.getName();
+          Model fromModel = nameModelMap.get(fromName);
+          Model toModel = nameModelMap.get(toName);
+          if (fromModel == null) {
+            throw new InvalidArgumentException(
+                "Mapping file references to " + fromName + " submodel. But such model doesn't exist");
+          } else if (toModel == null) {
+            throw new InvalidArgumentException(
+                "Mapping file references to " + toName + " submodel. But such model doesn't exist");
+          }
+          Element source = fromModel.getElementByElementId(fromAlias.getName());
+          if (source == null) {
+            throw new InvalidArgumentException("Mapping file references to element with alias: " + fromAlias.getName()
+                + ". But such element doesn't exist");
+          }
+          Element dest = null;
+          if (!(toAlias instanceof Complex)) {
+            dest = fromModel.getElementByElementId(toAlias.getName());
+          }
+          SubmodelType type = SubmodelType.UNKNOWN;
+          if (fromAlias instanceof Protein) {
+            type = SubmodelType.DOWNSTREAM_TARGETS;
+          } else if (fromAlias instanceof Phenotype) {
+            type = SubmodelType.PATHWAY;
+          }
+          ElementSubmodelConnection connection = new ElementSubmodelConnection(toModel, type);
+          connection.setFromElement(source);
+          connection.setToElement(dest);
+          connection.setName(toModel.getName());
+          source.setSubmodel(connection);
+        }
+      }
+    }
+  }
 
-	/**
-	 * This method validates if information about model and submodels in the
-	 * params are sufficient. If not then apropriate exception will be thrown.
-	 * 
-	 * @param params
-	 *          parameters to validate
-	 * @param zipFile
-	 *          original {@link ZipFile}
-	 * @return name of the file containg mapping between submodels
-	 */
-	protected String validateSubmodelInformation(ComplexZipConverterParams params, ZipFile zipFile) {
-		Enumeration<? extends ZipEntry> entries = zipFile.entries();
-		Set<String> processed = new HashSet<String>();
+  /**
+   * This method validates if information about model and submodels in the params
+   * are sufficient. If not then appropriate exception will be thrown.
+   * 
+   * @param params
+   *          parameters to validate
+   * @param zipFile
+   *          original {@link ZipFile}
+   * @return name of the file containing mapping between submodels
+   */
+  protected String validateSubmodelInformation(ComplexZipConverterParams params, ZipFile zipFile) {
+    Enumeration<? extends ZipEntry> entries = zipFile.entries();
+    Set<String> processed = new HashSet<>();
 
-		String root = null;
-		String mapping = null;
-		while (entries.hasMoreElements()) {
-			ZipEntry entry = entries.nextElement();
-			if (!entry.isDirectory()) {
-				String name = entry.getName();
-				ZipEntryFile zef = params.getEntry(name);
-				if (zef == null) {
-					throw new InvalidArgumentException("No information found in params about file: " + name);
-				}
-				if (zef instanceof ModelZipEntryFile) {
-					ModelZipEntryFile modelEntryFile = (ModelZipEntryFile) zef;
-					if (modelEntryFile.isRoot()) {
-						if (root != null) {
-							throw new InvalidArgumentException("Two roots found: " + name + ", " + root + ". There can be only one.");
-						}
-						root = name;
-					}
-					if (modelEntryFile.isMappingFile()) {
-						if (mapping != null) {
-							throw new InvalidArgumentException("Two mapping files found: " + name + ", " + mapping + ". There can be only one.");
-						}
-						mapping = name;
-					}
-				}
-				processed.add(name);
-			}
-		}
-		if (root == null) {
-			throw new InvalidArgumentException("No root map found.");
-		}
-		for (String entryName : params.getFilenames()) {
-			if (!processed.contains(entryName)) {
-				throw new InvalidArgumentException("Entry " + entryName + " doesn't exists in the zip file.");
-			}
-		}
-		return mapping;
-	}
+    String root = null;
+    String mapping = null;
+    logger.debug(params.getFilenames());
+    while (entries.hasMoreElements()) {
+      ZipEntry entry = entries.nextElement();
+      if (!entry.isDirectory()) {
+        String name = entry.getName();
+        ZipEntryFile zef = params.getEntry(name);
+        if (zef == null) {
+          throw new InvalidArgumentException("No information found in params about file: " + name);
+        }
+        if (zef instanceof ModelZipEntryFile) {
+          ModelZipEntryFile modelEntryFile = (ModelZipEntryFile) zef;
+          if (modelEntryFile.isRoot()) {
+            if (root != null) {
+              throw new InvalidArgumentException("Two roots found: " + name + ", " + root + ". There can be only one.");
+            }
+            root = name;
+          }
+          if (modelEntryFile.isMappingFile()) {
+            if (mapping != null) {
+              throw new InvalidArgumentException(
+                  "Two mapping files found: " + name + ", " + mapping + ". There can be only one.");
+            }
+            mapping = name;
+          }
+        }
+        processed.add(name.toLowerCase());
+      }
+    }
+    if (root == null) {
+      throw new InvalidArgumentException("No root map found.");
+    }
+    for (String entryName : params.getFilenames()) {
+      if (!processed.contains(entryName)) {
+        throw new InvalidArgumentException("Entry " + entryName + " doesn't exists in the zip file.");
+      }
+    }
+    return mapping;
+  }
 
-	/**
-	 * Transforms {@link DataMiningZipEntryFile} into {@link DataMiningSet}.
-	 * 
-	 * @param zipFile
-	 *          original {@link ZipFile}
-	 * @param entry
-	 *          entry in a zip file
-	 * @param dmEntry
-	 *          {@link DataMiningZipEntryFile} to transform
-	 * @return {@link DataMiningSet} for a given {@link DataMiningZipEntryFile}
-	 * @throws IOException
-	 *           thrown when there is a problem with accessing {@link ZipFile}
-	 */
-	protected DataMiningSet dataMiningZipEntryToDataMiningSet(ZipFile zipFile, ZipEntry entry, DataMiningZipEntryFile dmEntry) throws IOException {
-		DataMiningSet dmSet = new DataMiningSet();
-		dmSet.setName(dmEntry.getName());
-		dmSet.setInputData(IOUtils.toByteArray(zipFile.getInputStream(entry)));
-		dmSet.setDescription(dmEntry.getDescription());
-		dmSet.setSource(dmEntry.getSource());
-		dmSet.setType(dmEntry.getType());
-		return dmSet;
-	}
+  /**
+   * Transforms {@link DataMiningZipEntryFile} into {@link DataMiningSet}.
+   * 
+   * @param zipFile
+   *          original {@link ZipFile}
+   * @param entry
+   *          entry in a zip file
+   * @param dmEntry
+   *          {@link DataMiningZipEntryFile} to transform
+   * @return {@link DataMiningSet} for a given {@link DataMiningZipEntryFile}
+   * @throws IOException
+   *           thrown when there is a problem with accessing {@link ZipFile}
+   */
+  protected DataMiningSet dataMiningZipEntryToDataMiningSet(ZipFile zipFile, ZipEntry entry,
+      DataMiningZipEntryFile dmEntry) throws IOException {
+    DataMiningSet dmSet = new DataMiningSet();
+    dmSet.setName(dmEntry.getName());
+    dmSet.setInputData(IOUtils.toByteArray(zipFile.getInputStream(entry)));
+    dmSet.setDescription(dmEntry.getDescription());
+    dmSet.setSource(dmEntry.getSource());
+    dmSet.setType(dmEntry.getType());
+    return dmSet;
+  }
 
-	/**
-	 * Transforms {@link LayoutZipEntryFile} into {@link Layout}.
-	 * 
-	 * @param zipFile
-	 *          original {@link ZipFile}
-	 * @param entry
-	 *          entry in a zip file
-	 * @param params
-	 *          parameters used to make general conversion (we use directory where
-	 *          layout should be stored)
-	 * @param layoutEntry
-	 *          {@link LayoutZipEntryFile} to transform
-	 * @return {@link LAyout} for a given {@link LayoutZipEntryFile}
-	 * @throws IOException
-	 *           thrown when there is a problem with accessing {@link ZipFile}
-	 */
-	protected Layout layoutZipEntryFileToLayout(ComplexZipConverterParams params, ZipFile zipFile, ZipEntry entry, LayoutZipEntryFile layoutEntry)
-			throws IOException {
-		Layout layout = new Layout();
-		layout.setDescription(layoutEntry.getDescription());
-		layout.setDirectory(params.getVisualizationDir() + "/" + layoutEntry.getName().replaceAll(" ", "_"));
-		UploadedFileEntry fileEntry = new UploadedFileEntry();
-		fileEntry.setFileContent(IOUtils.toByteArray(zipFile.getInputStream(entry)));
-		fileEntry.setOriginalFileName(entry.getName());
-		layout.setInputData(fileEntry);
-		layout.setPublicLayout(true);
-		layout.setTitle(layoutEntry.getName());
-		return layout;
-	}
+  /**
+   * Transforms {@link LayoutZipEntryFile} into {@link Layout}.
+   * 
+   * @param zipFile
+   *          original {@link ZipFile}
+   * @param entry
+   *          entry in a zip file
+   * @param params
+   *          parameters used to make general conversion (we use directory where
+   *          layout should be stored)
+   * @param layoutEntry
+   *          {@link LayoutZipEntryFile} to transform
+   * @return {@link LAyout} for a given {@link LayoutZipEntryFile}
+   * @throws IOException
+   *           thrown when there is a problem with accessing {@link ZipFile}
+   */
+  protected Layout layoutZipEntryFileToLayout(ComplexZipConverterParams params, ZipFile zipFile, ZipEntry entry,
+      LayoutZipEntryFile layoutEntry) throws IOException {
+    Layout layout = new Layout();
+    layout.setDescription(layoutEntry.getDescription());
+    layout.setDirectory(params.getVisualizationDir() + "/" + layoutEntry.getName().replaceAll(" ", "_"));
+    UploadedFileEntry fileEntry = new UploadedFileEntry();
+    fileEntry.setFileContent(IOUtils.toByteArray(zipFile.getInputStream(entry)));
+    fileEntry.setOriginalFileName(entry.getName());
+    fileEntry.setLength(fileEntry.getFileContent().length);
+    layout.setInputData(fileEntry);
+    layout.setPublicLayout(true);
+    layout.setTitle(layoutEntry.getName());
+    return layout;
+  }
 
-	/**
-	 * Copy file from zip entry into temporary file.
-	 * 
-	 * @param zipFile
-	 *          input zip file
-	 * @param entry
-	 *          entry in the zip file
-	 * @return {@link File} with a copy of data from zip entry
-	 * @throws IOException
-	 *           thrown when there is a problem with input or output file
-	 */
-	protected File saveFileFromZipFile(ZipFile zipFile, ZipEntry entry) throws IOException {
-		InputStream is = zipFile.getInputStream(entry);
-		File result = File.createTempFile("temp-file-name", ".png");
-		FileOutputStream fos = new FileOutputStream(result);
-		byte[] bytes = new byte[BUFFER_SIZE];
-		int length;
-		while ((length = is.read(bytes)) >= 0) {
-			fos.write(bytes, 0, length);
-		}
-		fos.close();
-		return result;
-	}
+  /**
+   * Copy file from zip entry into temporary file.
+   * 
+   * @param zipFile
+   *          input zip file
+   * @param entry
+   *          entry in the zip file
+   * @return {@link File} with a copy of data from zip entry
+   * @throws IOException
+   *           thrown when there is a problem with input or output file
+   */
+  protected File saveFileFromZipFile(ZipFile zipFile, ZipEntry entry) throws IOException {
+    InputStream is = zipFile.getInputStream(entry);
+    File result = File.createTempFile("temp-file-name", ".png");
+    FileOutputStream fos = new FileOutputStream(result);
+    byte[] bytes = new byte[BUFFER_SIZE];
+    int length;
+    while ((length = is.read(bytes)) >= 0) {
+      fos.write(bytes, 0, length);
+    }
+    fos.close();
+    return result;
+  }
 
-	/**
-	 * Creates inctance of {@link IConverter} used as a template parameter for
-	 * this class instatiation.
-	 * 
-	 * @return inctance of {@link IConverter}
-	 */
-	protected IConverter createConverterInstance() {
-		IConverter converter;
-		try {
-			converter = converterClazz.newInstance();
-		} catch (InstantiationException e) {
-			throw new InvalidClassException("Problem with instantation of the class: " + converterClazz, e);
-		} catch (IllegalAccessException e) {
-			throw new InvalidClassException("Problem with instantation of the class: " + converterClazz, e);
-		}
-		return converter;
-	}
+  /**
+   * Creates inctance of {@link IConverter} used as a template parameter for this
+   * class instatiation.
+   * 
+   * @return inctance of {@link IConverter}
+   */
+  protected IConverter createConverterInstance() {
+    IConverter converter;
+    try {
+      converter = converterClazz.newInstance();
+    } catch (InstantiationException e) {
+      throw new InvalidClassException("Problem with instantation of the class: " + converterClazz, e);
+    } catch (IllegalAccessException e) {
+      throw new InvalidClassException("Problem with instantation of the class: " + converterClazz, e);
+    }
+    return converter;
+  }
 }
diff --git a/converter/src/main/java/lcsb/mapviewer/converter/ComplexZipConverterParams.java b/converter/src/main/java/lcsb/mapviewer/converter/ComplexZipConverterParams.java
index 2001d886edaea980a216be9fb586c2060a19d534..8d8daf907dbb0de4fd104a09537b0a8a3807de08 100644
--- a/converter/src/main/java/lcsb/mapviewer/converter/ComplexZipConverterParams.java
+++ b/converter/src/main/java/lcsb/mapviewer/converter/ComplexZipConverterParams.java
@@ -19,113 +19,112 @@ import lcsb.mapviewer.converter.zip.ZipEntryFile;
  */
 public class ComplexZipConverterParams {
 
-	/**
-	 * Default class logger.
-	 */
-	@SuppressWarnings("unused")
-	private final Logger							logger					 = Logger.getLogger(ComplexZipConverterParams.class);
-
-	/**
-	 * Zip file where all maps are stored.
-	 */
-	private ZipFile									 zipFile;
-
-	/**
-	 * Mapping between filename and information provided by the user about the
-	 * file.
-	 */
-	private Map<String, ZipEntryFile> entries					= new HashMap<>();
-
-	/**
-	 * Directory where additional visualization files should be stored.
-	 */
-	private String										visualizationDir = null;
-
-	/**
-	 * Sets {@link #zipFile}.
-	 * 
-	 * @param zipFile
-	 *          {@link #zipFile}
-	 * @return object with all parameters
-	 */
-	public ComplexZipConverterParams zipFile(ZipFile zipFile) {
-		this.zipFile = zipFile;
-		return this;
-	}
-
-	/**
-	 * Sets {@link #zipFile}.
-	 * 
-	 * @param filename
-	 *          name of the {@link #zipFile}
-	 * @return object with all parameters
-	 * @throws IOException
-	 *           throw when there is a problem with a file
-	 */
-	public ComplexZipConverterParams zipFile(String filename) throws IOException {
-		this.zipFile = new ZipFile(filename);
-		return this;
-	}
-
-	/**
-	 * Sets information about single entry in the zip file.
-	 * 
-	 * @param entry
-	 *          set of information about single zip entry
-	 * @return object with all parameters
-	 */
-	public ComplexZipConverterParams entry(ZipEntryFile entry) {
-		this.entries.put(entry.getFilename(), entry);
-		return this;
-	}
-
-	/**
-	 * @return the zipFile
-	 * @see #zipFile
-	 */
-	public ZipFile getZipFile() {
-		return zipFile;
-	}
-
-	/**
-	 * Returns set of filenames put in this param object.
-	 * 
-	 * @return set of filenames put in this param object
-	 */
-	public Set<String> getFilenames() {
-		return entries.keySet();
-	}
-
-	/**
-	 * Sets {@link #visualizationDir} value.
-	 * 
-	 * @param string
-	 *          new value
-	 * @return instance of this class
-	 */
-	public ComplexZipConverterParams visualizationDir(String string) {
-		this.visualizationDir = string;
-		return this;
-	}
-
-	/**
-	 * Returns {@link #visualizationDir}.
-	 * 
-	 * @return {@link #visualizationDir}
-	 */
-	public String getVisualizationDir() {
-		return visualizationDir;
-	}
-
-	/**
-	 * Return {@link ZipEntryFile entry} with information about single file in the
-	 * zip archive identified by file name.
-	 * 
-	 * @param name
-	 *          name of the file in zip archive
-	 * @return {@link ZipEntryFile entry} with information about file
-	 */
-	public ZipEntryFile getEntry(String name) {
-		return entries.get(name);
-	}
+  /**
+   * Default class logger.
+   */
+  @SuppressWarnings("unused")
+  private final Logger logger = Logger.getLogger(ComplexZipConverterParams.class);
+
+  /**
+   * Zip file where all maps are stored.
+   */
+  private ZipFile zipFile;
+
+  /**
+   * Mapping between filename and information provided by the user about the file.
+   */
+  private Map<String, ZipEntryFile> entries = new HashMap<>();
+
+  /**
+   * Directory where additional visualization files should be stored.
+   */
+  private String visualizationDir = null;
+
+  /**
+   * Sets {@link #zipFile}.
+   * 
+   * @param zipFile
+   *          {@link #zipFile}
+   * @return object with all parameters
+   */
+  public ComplexZipConverterParams zipFile(ZipFile zipFile) {
+    this.zipFile = zipFile;
+    return this;
+  }
+
+  /**
+   * Sets {@link #zipFile}.
+   * 
+   * @param filename
+   *          name of the {@link #zipFile}
+   * @return object with all parameters
+   * @throws IOException
+   *           throw when there is a problem with a file
+   */
+  public ComplexZipConverterParams zipFile(String filename) throws IOException {
+    this.zipFile = new ZipFile(filename);
+    return this;
+  }
+
+  /**
+   * Sets information about single entry in the zip file.
+   * 
+   * @param entry
+   *          set of information about single zip entry
+   * @return object with all parameters
+   */
+  public ComplexZipConverterParams entry(ZipEntryFile entry) {
+    this.entries.put(entry.getFilename().toLowerCase(), entry);
+    return this;
+  }
+
+  /**
+   * @return the zipFile
+   * @see #zipFile
+   */
+  public ZipFile getZipFile() {
+    return zipFile;
+  }
+
+  /**
+   * Returns set of filenames put in this param object.
+   * 
+   * @return set of filenames put in this param object
+   */
+  public Set<String> getFilenames() {
+    return entries.keySet();
+  }
+
+  /**
+   * Sets {@link #visualizationDir} value.
+   * 
+   * @param string
+   *          new value
+   * @return instance of this class
+   */
+  public ComplexZipConverterParams visualizationDir(String string) {
+    this.visualizationDir = string;
+    return this;
+  }
+
+  /**
+   * Returns {@link #visualizationDir}.
+   * 
+   * @return {@link #visualizationDir}
+   */
+  public String getVisualizationDir() {
+    return visualizationDir;
+  }
+
+  /**
+   * Return {@link ZipEntryFile entry} with information about single file in the
+   * zip archive identified by file name (file name is case insensitive).
+   * 
+   * @param name
+   *          name of the file in zip archive
+   * @return {@link ZipEntryFile entry} with information about file
+   */
+  public ZipEntryFile getEntry(String name) {
+    return entries.get(name.toLowerCase());
+  }
 }
diff --git a/converter/src/test/java/lcsb/mapviewer/converter/AllTests.java b/converter/src/test/java/lcsb/mapviewer/converter/AllTests.java
index f69bc17894122004b4ff0bd1f69def8e6998dd80..39feccf2106e947ca6dd4ac2b7efdc54c476d2e3 100644
--- a/converter/src/test/java/lcsb/mapviewer/converter/AllTests.java
+++ b/converter/src/test/java/lcsb/mapviewer/converter/AllTests.java
@@ -5,9 +5,10 @@ import org.junit.runners.Suite;
 import org.junit.runners.Suite.SuiteClasses;
 
 @RunWith(Suite.class)
-@SuiteClasses({ ComplexZipConverterTest.class, //
-		OverviewParserTest.class, //
-		ProjectFactoryTest.class,//
+@SuiteClasses({ ComplexZipConverterParamsTest.class, //
+    ComplexZipConverterTest.class, //
+    OverviewParserTest.class, //
+    ProjectFactoryTest.class,//
 })
 public class AllTests {
 
diff --git a/converter/src/test/java/lcsb/mapviewer/converter/ComplexZipConverterParamsTest.java b/converter/src/test/java/lcsb/mapviewer/converter/ComplexZipConverterParamsTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..c3ba1883c4c49cced7240d7fc1a2eda60e23386e
--- /dev/null
+++ b/converter/src/test/java/lcsb/mapviewer/converter/ComplexZipConverterParamsTest.java
@@ -0,0 +1,22 @@
+package lcsb.mapviewer.converter;
+
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Test;
+
+import lcsb.mapviewer.converter.zip.LayoutZipEntryFile;
+import lcsb.mapviewer.converter.zip.ZipEntryFile;
+
+public class ComplexZipConverterParamsTest {
+
+  @Test
+  public void testCaseInsensivity() {
+    ComplexZipConverterParams params = new ComplexZipConverterParams();
+    ZipEntryFile entry = new LayoutZipEntryFile("TEST.xml", "test", null);
+    params.entry(entry);
+    assertNotNull(params.getEntry("TEST.xml"));
+    assertNotNull(params.getEntry("test.xml"));
+    assertNotNull(params.getEntry("TEST.XML"));
+  }
+
+}
diff --git a/frontend-js/.gitignore b/frontend-js/.gitignore
index e162e8adca015a9ebebd6bcd58700fecf273bd80..eddc4c991d95d14d7bf07121b3b7009939654019 100644
--- a/frontend-js/.gitignore
+++ b/frontend-js/.gitignore
@@ -1,7 +1,9 @@
 .idea/workspace.xml
+.idea/jsLibraryMappings.xml
 .idea/dictionaries
 
 /dist/
 /coverage/
 /node_modules/
 /npm-debug.log
+
diff --git a/frontend-js/src/main/js/ServerConnector.js b/frontend-js/src/main/js/ServerConnector.js
index 0bf92f6d705ec7ca0210ef65756e9c83f03324f1..584e1a8d7e7a45f787765f4eaa9989da1daeaca0 100644
--- a/frontend-js/src/main/js/ServerConnector.js
+++ b/frontend-js/src/main/js/ServerConnector.js
@@ -155,7 +155,10 @@ ServerConnector._sendRequest = function (params) {
   return new Promise(function (resolve, reject) {
     request(params, function (error, response, body) {
       if (error) {
-        reject(error);
+        reject(new NetworkError(error.message, {
+          content: body,
+          url: url
+        }));
       } else if (response.statusCode !== 200) {
         reject(new NetworkError(params.url + " rejected with status code: " + response.statusCode, {
           content: body,
@@ -201,8 +204,9 @@ ServerConnector.sendPatchRequest = function (url, json) {
 ServerConnector.getToken = function () {
   var self = this;
 
+  var login = self.getSessionData(null).getLogin()
   var token = self.getSessionData(null).getToken();
-  if (token === undefined) {
+  if (token === undefined || login === undefined) {
     return self.login();
   } else {
     // if the project is not initialized then check if we can download data
@@ -228,8 +232,8 @@ ServerConnector.getApiBaseUrl = function () {
 ServerConnector.getServerBaseUrl = function () {
   if (this._serverBaseUrl === undefined) {
     var url = "" + window.location.href;
-    if (url.indexOf("?")>=0) {
-      url = url.substr(0,url.indexOf("?"));
+    if (url.indexOf("?") >= 0) {
+      url = url.substr(0, url.indexOf("?"));
     }
     if (!url.endsWith("/")) {
       url = url.substr(0, url.lastIndexOf("/") + 1);
@@ -565,6 +569,30 @@ ServerConnector.getProjectSourceUrl = function (queryParams, filterParams) {
   });
 };
 
+
+ServerConnector.getFilesUrl = function () {
+  return this.getApiUrl({
+    type: "files/"
+  });
+};
+
+ServerConnector.getCreateFileUrl = function () {
+  return this.getApiUrl({
+    url: this.getFilesUrl()
+  });
+};
+ServerConnector.getFileUrl = function (queryParams) {
+  return this.getApiUrl({
+    url: this.getFilesUrl() + "/" + queryParams.id
+  });
+};
+ServerConnector.getUploadFileUrl = function (queryParams) {
+  return this.getApiUrl({
+    url: this.getFileUrl(queryParams) + ":uploadContent"
+  });
+};
+
+
 ServerConnector.getUsersUrl = function (queryParams, filterParams) {
   return this.getApiUrl({
     type: "users/",
@@ -1414,7 +1442,7 @@ ServerConnector.addComment = function (params) {
     elementId: params.elementId,
     elementType: params.elementType,
     coordinates: self.pointToString(params.coordinates),
-    modelId: params.modelId,
+    modelId: params.modelId
   };
   var filterParams = params;
   delete filterParams.elementId;
@@ -1445,7 +1473,7 @@ ServerConnector.addOverlay = function (params) {
     name: overlay.getName(),
     description: overlay.getDescription(),
     content: overlay.getContent(),
-    filename: overlay.getFilename(),
+    filename: overlay.getFilename()
   };
   return self.getProjectId(params.projectId).then(function (result) {
     queryParams.projectId = result;
@@ -1458,14 +1486,14 @@ ServerConnector.addOverlay = function (params) {
 ServerConnector.updateOverlay = function (overlay) {
   var self = this;
   var queryParams = {
-    overlayId: overlay.getId(),
+    overlayId: overlay.getId()
   };
   var filterParams = {
     overlay: {
       name: overlay.getName(),
       description: overlay.getDescription(),
       creator: overlay.getCreator(),
-      publicOverlay: overlay.getPublicOverlay(),
+      publicOverlay: overlay.getPublicOverlay()
     }
   };
   return self.sendPatchRequest(self.updateOverlayUrl(queryParams), filterParams);
@@ -1526,7 +1554,7 @@ ServerConnector.getPublications = function (params) {
     length: params.length,
     sortColumn: params.sortColumn,
     sortOrder: params.sortOrder,
-    search: params.search,
+    search: params.search
   };
   return self.getProjectId(params.projectId).then(function (result) {
     queryParams.projectId = result;
@@ -1544,4 +1572,34 @@ ServerConnector.getReferenceGenome = function (params) {
   });
 };
 
+ServerConnector.uploadFile = function (params) {
+  var CHUNK_SIZE = 65535;
+  var self = this;
+  var data = new Uint8Array(params.content);
+  var filterParams = {
+    filename: params.filename,
+    length: data.length
+  };
+
+  return self.sendPostRequest(self.getCreateFileUrl(), filterParams).then(function (response) {
+    var uploadedLength = 0;
+    var createPromise = function (resultFileJson) {
+      var resultFile = JSON.parse(resultFileJson);
+      if (uploadedLength >= data.length) {
+        return Promise.resolve(resultFile);
+      } else {
+        var chunk = data.slice(uploadedLength, uploadedLength + CHUNK_SIZE);
+        logger.debug("SEND " + chunk.length + " bytes");
+        var url = self.getUploadFileUrl({id: resultFile.id});
+        return self.sendRequest({method: "POST", url: url, body: chunk}).then(function (resultFileJson) {
+          uploadedLength += chunk.length;
+          logger.debug("RESPONSE ", resultFileJson);
+          return createPromise(resultFileJson);
+        })
+      }
+    };
+    return createPromise(response);
+  });
+};
+
 module.exports = ServerConnector;
diff --git a/frontend-js/src/main/js/gui/admin/AddProjectDialog.js b/frontend-js/src/main/js/gui/admin/AddProjectDialog.js
index 966d914461424cdbc1c4fb1672b782fa37b0c029..c6766dbec447d8b034f79c6f2a135411e4d0e824 100644
--- a/frontend-js/src/main/js/gui/admin/AddProjectDialog.js
+++ b/frontend-js/src/main/js/gui/admin/AddProjectDialog.js
@@ -675,7 +675,7 @@ AddProjectDialog.prototype.processFile = function (file) {
   if (file) {
     return new Promise(function (resolve, reject) {
       var reader = new FileReader();
-      reader.readAsText(file);
+      reader.readAsArrayBuffer(file);
       reader.onload = function (evt) {
         try {
           self.setFileContent(evt.target.result);
@@ -694,7 +694,6 @@ AddProjectDialog.prototype.processFile = function (file) {
 };
 
 AddProjectDialog.prototype.setFileContent = function (fileContent) {
-  logger.debug(fileContent);
   this._fileContent = fileContent;
 };
 AddProjectDialog.prototype.getFileContent = function () {
@@ -771,6 +770,7 @@ AddProjectDialog.prototype.setSemanticZooming = function (value) {
 
 AddProjectDialog.prototype.setFileParserForFilename = function (filename) {
   var self = this;
+  self._filename = filename;
   var select = $("[name='project-format']", self.getElement)[0];
   var options = select.options;
   var optionId = 0;
@@ -803,18 +803,20 @@ AddProjectDialog.prototype.getConverter = function () {
 
 AddProjectDialog.prototype.onSaveClicked = function () {
   var self = this;
+  var parserClass;
   return self.checkValidity().then(function () {
     return self.getConverter();
   }).then(function (converter) {
-    var parserClass;
     if (converter !== null) {
       parserClass = converter.handler;
     }
+    return ServerConnector.uploadFile({filename: self._filename, content: self.getFileContent()});
+  }).then(function (file) {
     var options = {
       "projectId": self.getProjectId(),
       "name": self.getName(),
       "parser": parserClass,
-      "file-content": self.getFileContent(),
+      "file-id": file.id,
       "auto-resize": self.isAutoMargin(),
       "cache": self.isCache(),
       "notify-email": self.getNotifyEmail(),
@@ -978,4 +980,8 @@ AddProjectDialog.prototype.getEntryByFilename = function (filename) {
   return null;
 };
 
+AddProjectDialog.prototype.getFilename = function () {
+  return this._filename;
+};
+
 module.exports = AddProjectDialog;
diff --git a/frontend-js/src/test/js/ServerConnector-test.js b/frontend-js/src/test/js/ServerConnector-test.js
index ab6fc4ec0aae1c5c68dee7784bda6ce8566d4871..0e756aae632c8c549b248650cb783ba357c32cd4 100644
--- a/frontend-js/src/test/js/ServerConnector-test.js
+++ b/frontend-js/src/test/js/ServerConnector-test.js
@@ -20,80 +20,80 @@ var logger = require('./logger');
 var chai = require('chai');
 var assert = chai.assert;
 
-describe('ServerConnector', function() {
-  describe('getProject', function() {
-    it('default', function() {
-      return ServerConnector.getProject().then(function(result) {
+describe('ServerConnector', function () {
+  describe('getProject', function () {
+    it('default', function () {
+      return ServerConnector.getProject().then(function (result) {
         assert.ok(result instanceof Project);
         assert.equal(result.getProjectId(), "sample");
         assert.equal(logger.getWarnings().length, 0);
       });
     });
-    it('invalid project id', function() {
-      return ServerConnector.getProject("invalid_project_id").then(function(result) {
+    it('invalid project id', function () {
+      return ServerConnector.getProject("invalid_project_id").then(function (result) {
         assert.equal(result, null);
       });
     });
-    it('caching', function() {
+    it('caching', function () {
       var project;
-      return ServerConnector.getProject().then(function(result) {
+      return ServerConnector.getProject().then(function (result) {
         project = result;
         return ServerConnector.getProject();
 
-      }).then(function(result) {
+      }).then(function (result) {
         assert.ok(result === project);
       });
     });
   });
 
-  describe('updateProject', function() {
-    it('default', function() {
+  describe('updateProject', function () {
+    it('default', function () {
       var project;
       var newVersion = "2.01";
-      return ServerConnector.getProject().then(function(result) {
+      return ServerConnector.getProject().then(function (result) {
         project = result;
         project.setVersion(newVersion);
         return ServerConnector.updateProject(project);
-      }).then(function(result) {
+      }).then(function (result) {
         assert.ok(project === result);
         assert.equal(newVersion, result.getVersion());
       });
     });
   });
-  describe('removeProject', function() {
-    it('default', function() {
+  describe('removeProject', function () {
+    it('default', function () {
       var project;
-      return ServerConnector.getProject().then(function(result) {
+      return ServerConnector.getProject().then(function (result) {
         project = result;
         return ServerConnector.removeProject(project.getProjectId());
-      }).then(function(result) {
+      }).then(function (result) {
         assert.ok(project === result);
       });
     });
   });
 
-  it('getModels', function() {
-    return ServerConnector.getModels("sample").then(function(models) {
+  it('getModels', function () {
+    return ServerConnector.getModels("sample").then(function (models) {
       assert.equal(1, models.length);
       assert.ok(models[0] instanceof MapModel);
     });
   });
 
-  it('getPublications', function() {
-    return ServerConnector.getPublications().then(function(result) {
+  it('getPublications', function () {
+    return ServerConnector.getPublications().then(function (result) {
       assert.equal(result.totalSize, 1);
     });
   });
 
-  it('getProjectId from GET params', function() {
+  it('getProjectId from GET params', function () {
     helper.setUrl("http://test/?id=test");
-    return ServerConnector.getProjectId().then(function(result) {
+    return ServerConnector.getProjectId().then(function (result) {
       assert.equal(result, "test");
     });
   });
 
-  it('getReactions with empty list of ids', function() {
-    return ServerConnector.getReactions([]).then(function(result) {
+  it('getReactions with empty list of ids', function () {
+    return ServerConnector.getReactions([]).then(function (result) {
       assert.equal(result.length, 2);
       var reaction = result[0];
       assert.ok(reaction instanceof Reaction);
@@ -102,8 +102,8 @@ describe('ServerConnector', function() {
     });
   });
 
-  it('getReactions without ids', function() {
-    return ServerConnector.getReactions([]).then(function(result) {
+  it('getReactions without ids', function () {
+    return ServerConnector.getReactions([]).then(function (result) {
       assert.equal(result.length, 2);
       var reaction = result[0];
       assert.ok(reaction instanceof Reaction);
@@ -112,8 +112,8 @@ describe('ServerConnector', function() {
     });
   });
 
-  it('getElements with empty list of ids', function() {
-    return ServerConnector.getAliases({}).then(function(result) {
+  it('getElements with empty list of ids', function () {
+    return ServerConnector.getAliases({}).then(function (result) {
       assert.equal(result.length, 30);
       var alias = result[0];
       assert.ok(alias instanceof Alias);
@@ -121,8 +121,8 @@ describe('ServerConnector', function() {
     });
   });
 
-  it('getOverlayElements', function() {
-    return ServerConnector.getOverlayElements(18077).then(function(result) {
+  it('getOverlayElements', function () {
+    return ServerConnector.getOverlayElements(18077).then(function (result) {
       assert.equal(result.length, 1);
       var layoutAlias = result[0];
       assert.ok(layoutAlias instanceof LayoutAlias);
@@ -132,80 +132,80 @@ describe('ServerConnector', function() {
     });
   });
 
-  it('idsToString', function() {
-    var ids = [ 3, 2, 9, 1, 6, 8, 3, 2, 9, 1, 7, 3 ];
+  it('idsToString', function () {
+    var ids = [3, 2, 9, 1, 6, 8, 3, 2, 9, 1, 7, 3];
     var str = ServerConnector.idsToString(ids);
     assert.equal(str, "1,2,3,6,7,8,9");
   });
 
-  it('getOverlaySourceDownloadUrl', function() {
+  it('getOverlaySourceDownloadUrl', function () {
     var id = 17296;
     return ServerConnector.getOverlaySourceDownloadUrl({
-      overlayId : id
-    }).then(function(url) {
+      overlayId: id
+    }).then(function (url) {
       assert.ok(url);
       assert.ok(url.indexOf(id) >= 0);
       return ServerConnector.sendGetRequest(url);
     });
   });
 
-  it('getImageDownloadUrl', function() {
+  it('getImageDownloadUrl', function () {
     var modelId = 15781;
     return ServerConnector.getImageDownloadUrl({
-      modelId : modelId,
-      handlerClass : "lcsb.mapviewer.converter.graphics.PngImageGenerator",
-    }).then(function(url) {
+      modelId: modelId,
+      handlerClass: "lcsb.mapviewer.converter.graphics.PngImageGenerator",
+    }).then(function (url) {
       assert.ok(url);
       assert.ok(url.indexOf(modelId) >= 0);
       return ServerConnector.sendGetRequest(url);
     });
   });
 
-  it('getModelDownloadUrl', function() {
+  it('getModelDownloadUrl', function () {
     var modelId = 15781;
     return ServerConnector.getModelDownloadUrl({
-      modelId : modelId,
-      handlerClass : "lcsb.mapviewer.converter.model.celldesigner.CellDesignerXmlParser",
-    }).then(function(url) {
+      modelId: modelId,
+      handlerClass: "lcsb.mapviewer.converter.model.celldesigner.CellDesignerXmlParser",
+    }).then(function (url) {
       assert.ok(url);
       assert.ok(url.indexOf(modelId) >= 0);
       return ServerConnector.sendGetRequest(url);
     });
   });
 
-  it('getProjectSourceDownloadUrl', function() {
-    return ServerConnector.getProjectSourceDownloadUrl().then(function(url) {
+  it('getProjectSourceDownloadUrl', function () {
+    return ServerConnector.getProjectSourceDownloadUrl().then(function (url) {
       assert.ok(url);
       return ServerConnector.sendGetRequest(url);
     });
   });
 
-  it('addOverlay', function() {
+  it('addOverlay', function () {
     return ServerConnector.addOverlay({
-      overlay : new LayoutData({
-        name : "test nam",
-        description : "test desc",
-        content : "name color\nCAPN1 #00FF00\nPARK7 #AC0000",
-        filename : "test.txt"
+      overlay: new LayoutData({
+        name: "test nam",
+        description: "test desc",
+        content: "name color\nCAPN1 #00FF00\nPARK7 #AC0000",
+        filename: "test.txt"
       }),
-    }).then(function(overlay) {
+    }).then(function (overlay) {
       assert.ok(overlay);
     });
   });
 
-  it('removeOverlay', function() {
+  it('removeOverlay', function () {
     return ServerConnector.removeOverlay({
-      overlayId : 17296,
+      overlayId: 17296,
     });
   });
 
-  it('removeComment', function() {
+  it('removeComment', function () {
     return ServerConnector.removeComment({
-      commentId : 4290,
+      commentId: 4290,
     });
   });
 
-  it('updateOverlay', function() {
+  it('updateOverlay', function () {
     var overlay = new LayoutData({});
     overlay.setId(17296);
     overlay.setName("test nam2");
@@ -214,142 +214,153 @@ describe('ServerConnector', function() {
     return ServerConnector.updateOverlay(overlay);
   });
 
-  it('logout', function() {
-    return ServerConnector.logout().then(function() {
+  it('logout', function () {
+    return ServerConnector.logout().then(function () {
       assert.equal(ServerConnector.getSessionData().getToken(), undefined);
     });
   });
 
-  it('getToken', function() {
+  it('getToken', function () {
     ServerConnector.getSessionData(null).setToken(undefined);
 
-    return ServerConnector.getToken().then(function(token) {
+    return ServerConnector.getToken().then(function (token) {
       assert.ok(token !== undefined);
     });
   });
 
-  it('getModelDownloadUrl', function() {
+  it('getModelDownloadUrl', function () {
     return ServerConnector.getModelDownloadUrl({
-      backgroundOverlayId : "cv14081",
-    }).then(function(url) {
+      backgroundOverlayId: "cv14081",
+    }).then(function (url) {
       assert.ok(url);
     });
   });
 
-  it('getOverlayById', function() {
-    return ServerConnector.getOverlayById(18083, "complex_model_with_submaps").then(function(overlay) {
+  it('getOverlayById', function () {
+    return ServerConnector.getOverlayById(18083, "complex_model_with_submaps").then(function (overlay) {
       assert.ok(overlay);
     });
   });
 
-  it('getConfiguration', function() {
-    return ServerConnector.getConfiguration().then(function(configuration) {
+  it('getConfiguration', function () {
+    return ServerConnector.getConfiguration().then(function (configuration) {
       assert.ok(configuration instanceof Configuration);
       assert.ok(configuration.getElementTypes().length > 0);
       assert.ok(configuration.getReactionTypes().length > 0);
     });
   });
 
-  describe('getProjects', function() {
-    it('test caching', function() {
+  describe('getProjects', function () {
+    it('test caching', function () {
       var projects;
-      return ServerConnector.getProjects().then(function(result) {
+      return ServerConnector.getProjects().then(function (result) {
         projects = result;
         return ServerConnector.getProjects();
-      }).then(function(result) {
+      }).then(function (result) {
         assert.ok(result === projects);
       });
     });
 
-    it('test force reload', function() {
+    it('test force reload', function () {
       var projects;
       var originalName;
-      return ServerConnector.getProjects().then(function(result) {
+      return ServerConnector.getProjects().then(function (result) {
         projects = result;
         originalName = projects[0].getName();
         projects[0].setName("test name");
         return ServerConnector.getProjects(true);
-      }).then(function(result) {
+      }).then(function (result) {
         assert.ok(result === projects);
         assert.equal(originalName, projects[0].getName());
       });
     });
   });
 
-  describe('login', function() {
-    it('try invalid credentials', function() {
+  describe('login', function () {
+    it('try invalid credentials', function () {
       var method = ServerConnector.sendPostRequest;
-      ServerConnector.sendPostRequest = function() {
+      ServerConnector.sendPostRequest = function () {
         return Promise.reject(new NetworkError("xxx", {
-          statusCode : HttpStatus.FORBIDDEN
+          statusCode: HttpStatus.FORBIDDEN
         }));
       };
-      return ServerConnector.login("unknown", "unknown password").then(function() {
+      return ServerConnector.login("unknown", "unknown password").then(function () {
         ServerConnector.sendPostRequest = method;
         assert.ok(false);
-      }, function(error) {
+      }, function (error) {
         ServerConnector.sendPostRequest = method;
         assert.ok(error.message.indexOf("credentials") >= 0);
       });
     });
   });
 
-    describe('getServerBaseUrl', function() {
-        it('url with GET arg that looks similar to original url', function() {
-            helper.setUrl("http://localhost:8080/minerva/login.xhtml?from=http://localhost:8080/minerva/?id=sample");
-            var url = ServerConnector.getServerBaseUrl();
-            assert.ok(url.indexOf("?")===-1);
-        });
+  describe('getServerBaseUrl', function () {
+    it('url with GET arg that looks similar to original url', function () {
+      helper.setUrl("http://localhost:8080/minerva/login.xhtml?from=http://localhost:8080/minerva/?id=sample");
+      var url = ServerConnector.getServerBaseUrl();
+      assert.ok(url.indexOf("?") === -1);
     });
+  });
 
 
-
-  describe('returnUserOrSystemColor ', function() {
-    it('user has empty color', function() {
+  describe('returnUserOrSystemColor ', function () {
+    it('user has empty color', function () {
       var systemColor = {};
-      return ServerConnector.returnUserOrSystemColor("", Promise.resolve(systemColor)).then(function(result) {
+      return ServerConnector.returnUserOrSystemColor("", Promise.resolve(systemColor)).then(function (result) {
         assert.ok(result = systemColor);
       });
     });
-    it('user has defined color', function() {
+    it('user has defined color', function () {
       var userColor = {};
       var systemColor = {};
-      return ServerConnector.returnUserOrSystemColor(userColor, Promise.resolve(systemColor)).then(function(result) {
+      return ServerConnector.returnUserOrSystemColor(userColor, Promise.resolve(systemColor)).then(function (result) {
         assert.ok(result = userColor);
       });
     });
   });
 
-  describe('readFile', function() {
-    it('check session expired', function() {
+  describe('readFile', function () {
+    it('check session expired', function () {
       ServerConnector.getSessionData().setToken(undefined);
       assert.ok(ServerConnector.getSessionData().getLogin());
-      return ServerConnector.sendGetRequest("package.json", "Downloading projects").then(function() {
+      return ServerConnector.sendGetRequest("package.json", "Downloading projects").then(function () {
         assert.notOk(ServerConnector.getSessionData().getLogin());
       });
     });
   });
 
-  describe('getUsers', function() {
-    it('default', function() {
-      return ServerConnector.getUsers().then(function(users) {
+  describe('getUsers', function () {
+    it('default', function () {
+      return ServerConnector.getUsers().then(function (users) {
         assert.ok(users.length > 0);
       });
     });
-    it('refresh', function() {
+    it('refresh', function () {
       var user;
       var users;
       var modifiedName = "xxx name";
-      return ServerConnector.getUsers().then(function(result) {
+      return ServerConnector.getUsers().then(function (result) {
         users = result;
         user = users[0];
         user.setName(modifiedName);
         return ServerConnector.getUsers(true);
-      }).then(function(result) {
+      }).then(function (result) {
         assert.ok(users === result);
         assert.ok(user.getName() !== modifiedName);
       });
     });
   });
 
+  describe('uploadFile', function () {
+    it('small file', function () {
+      return ServerConnector.uploadFile({
+        filename: "test.txt",
+        content: new Uint8Array([1, 65, 90, 4, 8])
+      }).then(function (file) {
+        logger.debug(file);
+        assert.ok(file.id);
+      });
+    });
+  });
+
 });
diff --git a/frontend-js/src/test/js/gui/admin/AddProjectDialog-test.js b/frontend-js/src/test/js/gui/admin/AddProjectDialog-test.js
index 219804ccf82bbf0ebbaabdd3a1e6310c06c6a63f..3e1807a01672c66e5c3631be2774160c1df0ccf6 100644
--- a/frontend-js/src/test/js/gui/admin/AddProjectDialog-test.js
+++ b/frontend-js/src/test/js/gui/admin/AddProjectDialog-test.js
@@ -139,7 +139,7 @@ describe('AddProjectDialog', function () {
       }).then(function () {
         assert.ok(options["name"] !== undefined);
         assert.ok(options["projectId"] !== undefined);
-        assert.ok(options["file-content"] !== undefined);
+        assert.ok(options["file-id"] !== undefined);
         assert.ok(options["parser"] !== undefined);
         assert.ok(options["auto-resize"] !== undefined);
         assert.ok(options["cache"] !== undefined);
@@ -148,6 +148,7 @@ describe('AddProjectDialog', function () {
         assert.ok(options["organism"] !== undefined);
         assert.ok(options["sbgn"] !== undefined);
         assert.ok(options["semantic-zoom"] !== undefined);
+      }).finally(function () {
         return dialog.destroy();
       });
     });
diff --git a/frontend-js/testFiles/apiCalls/files/6790.uploadContent/POST_token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/files/6790.uploadContent/POST_token=MOCK_TOKEN_ID&
new file mode 100644
index 0000000000000000000000000000000000000000..b5a2599fb1f6f4c086c68b650732f1e235774a5e
--- /dev/null
+++ b/frontend-js/testFiles/apiCalls/files/6790.uploadContent/POST_token=MOCK_TOKEN_ID&
@@ -0,0 +1,7 @@
+{
+    "owner": "admin",
+    "filename": "test.txt",
+    "uploadedDataLength": 5,
+    "length": 5,
+    "id": 6790
+}
\ No newline at end of file
diff --git a/frontend-js/testFiles/apiCalls/files/6791.uploadContent/POST_token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/files/6791.uploadContent/POST_token=MOCK_TOKEN_ID&
new file mode 100644
index 0000000000000000000000000000000000000000..78115f94a8a8795a09c5b29e05a5b6d7dd1ef5a6
--- /dev/null
+++ b/frontend-js/testFiles/apiCalls/files/6791.uploadContent/POST_token=MOCK_TOKEN_ID&
@@ -0,0 +1,7 @@
+{
+    "owner": "admin",
+    "filename": "test.xml",
+    "uploadedDataLength": 13,
+    "length": 13,
+    "id": 6791
+}
\ No newline at end of file
diff --git a/frontend-js/testFiles/apiCalls/files/POST_filename=test.txt&length=5&token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/files/POST_filename=test.txt&length=5&token=MOCK_TOKEN_ID&
new file mode 100644
index 0000000000000000000000000000000000000000..bd4d1f74f1fde7b5ef4c90e760f93513bb7aa951
--- /dev/null
+++ b/frontend-js/testFiles/apiCalls/files/POST_filename=test.txt&length=5&token=MOCK_TOKEN_ID&
@@ -0,0 +1,7 @@
+{
+    "owner": "admin",
+    "filename": "test.txt",
+    "uploadedDataLength": 0,
+    "length": 5,
+    "id": 6790
+}
\ No newline at end of file
diff --git a/frontend-js/testFiles/apiCalls/files/POST_filename=test.xml&length=13&token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/files/POST_filename=test.xml&length=13&token=MOCK_TOKEN_ID&
new file mode 100644
index 0000000000000000000000000000000000000000..232463c23bc5be9fdd67945940b9d246ef9d5da3
--- /dev/null
+++ b/frontend-js/testFiles/apiCalls/files/POST_filename=test.xml&length=13&token=MOCK_TOKEN_ID&
@@ -0,0 +1,7 @@
+{
+    "owner": "admin",
+    "filename": "test.xml",
+    "uploadedDataLength": 0,
+    "length": 13,
+    "id": 6791
+}
\ No newline at end of file
diff --git a/model/src/main/java/lcsb/mapviewer/model/cache/UploadedFileEntry.java b/model/src/main/java/lcsb/mapviewer/model/cache/UploadedFileEntry.java
index 0ef884497024c58c9ff0ef84b6b45bdd08b31a7a..acecea373d16991bf36b4bc6f2046716bc2b9e0a 100644
--- a/model/src/main/java/lcsb/mapviewer/model/cache/UploadedFileEntry.java
+++ b/model/src/main/java/lcsb/mapviewer/model/cache/UploadedFileEntry.java
@@ -4,6 +4,10 @@ import java.io.Serializable;
 
 import javax.persistence.DiscriminatorValue;
 import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.ManyToOne;
+
+import lcsb.mapviewer.model.user.User;
 
 /**
  * Database object representing file uploaded into system.
@@ -15,26 +19,50 @@ import javax.persistence.Entity;
 @DiscriminatorValue("UPLOADED_FILE_ENTRY")
 public class UploadedFileEntry extends FileEntry implements Serializable {
 
-	/**
-	 * 
-	 */
-	private static final long serialVersionUID = 1L;
-
-	/**
-	 * Default constructor.
-	 */
-	public UploadedFileEntry() {
-
-	}
-
-	/**
-	 * Constructor that copies data from the parameter.
-	 * 
-	 * @param original
-	 *          original object from which data will bbe copied
-	 */
-	public UploadedFileEntry(UploadedFileEntry original) {
-		super(original);
-	}
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * Length of the file.
+   */
+  private long length;
+
+  @ManyToOne(fetch = FetchType.LAZY)
+  private User owner;
+
+  /**
+   * Default constructor.
+   */
+  public UploadedFileEntry() {
+
+  }
+
+  /**
+   * Constructor that copies data from the parameter.
+   * 
+   * @param original
+   *          original object from which data will bbe copied
+   */
+  public UploadedFileEntry(UploadedFileEntry original) {
+    super(original);
+  }
+
+  public long getLength() {
+    return length;
+  }
+
+  public void setLength(long length) {
+    this.length = length;
+  }
+
+  public User getOwner() {
+    return owner;
+  }
+
+  public void setOwner(User owner) {
+    this.owner = owner;
+  }
 
 }
diff --git a/persist/src/db/11.1.0/fix_db_20171004.sql b/persist/src/db/11.1.0/fix_db_20171004.sql
new file mode 100644
index 0000000000000000000000000000000000000000..bf80845a974c170d8cb5ea72f3305ef816965810
--- /dev/null
+++ b/persist/src/db/11.1.0/fix_db_20171004.sql
@@ -0,0 +1,12 @@
+--uploaded files that are uploaded in chunks should have info about how big should be the file
+alter table file_entry add column length bigint;
+update file_entry set length = octet_length(filecontent);
+
+--add foreign key
+alter table file_entry add column owner_iddb integer;
+ALTER TABLE file_entry ADD CONSTRAINT file_entry_owner_constraint FOREIGN KEY (owner_iddb)
+      REFERENCES public.user_table (iddb) MATCH SIMPLE
+      ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+--add owners for layout files 
+update file_entry SET owner_iddb = (select (max(creator_iddb)) from layout where file_entry_iddb = file_entry.iddb);      
\ No newline at end of file
diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/BaseRestImpl.java b/rest-api/src/main/java/lcsb/mapviewer/api/BaseRestImpl.java
index 9918dfa4cfdfe63d7387a30621efa46f51058987..7729b2296f350d780e041feca5b89daa60eea2a7 100644
--- a/rest-api/src/main/java/lcsb/mapviewer/api/BaseRestImpl.java
+++ b/rest-api/src/main/java/lcsb/mapviewer/api/BaseRestImpl.java
@@ -38,263 +38,264 @@ import lcsb.mapviewer.services.view.AnnotationView;
 @Transactional(value = "txManager")
 public abstract class BaseRestImpl {
 
-	/**
-	 * Default class logger.
-	 */
-	private Logger					logger = Logger.getLogger(BaseRestImpl.class);
-
-	@Autowired
-	private IModelService		modelService;
-
-	@Autowired
-	private IProjectService	projectService;
-
-	@Autowired
-	private IUserService		userService;
-
-	@Autowired
-	private MiriamConnector	miriamConnector;
-
-	@Autowired
-	private PubmedParser		pubmedParser;
-
-	@Autowired
-	private ElementMatcher	elementMatcher;
-
-	protected Map<String, Object> okStatus() {
-		Map<String, Object> result = new HashMap<>();
-		return result;
-	}
-
-	protected Map<String, Object> createMinifiedSearchResult(Object object) {
-		Map<String, Object> result = new HashMap<>();
-		if (object instanceof Element) {
-			result.put("type", ElementIdentifierType.ALIAS);
-			Element element = (Element) object;
-			result.put("id", element.getId());
-			result.put("modelId", element.getModel().getId());
-		} else if (object instanceof Reaction) {
-			result.put("type", ElementIdentifierType.REACTION);
-			Reaction element = (Reaction) object;
-			result.put("id", element.getId());
-			result.put("modelId", element.getModel().getId());
-
-		} else {
-			throw new InvalidStateException("Unknown type of result: " + object.getClass());
-		}
-		return result;
-	};
-
-	protected Map<String, Object> createAnnotation(MiriamData annotation) {
-		if (annotation != null && annotation.getDataType() != null) {
-			Map<String, Object> result = new HashMap<>();
-			if (annotation.getDataType().getUris().size() > 0) {
-				try {
-					result.put("link", miriamConnector.getUrlString(annotation));
-				} catch (Exception e) {
-					logger.error("Problem with miriam: " + annotation, e);
-				}
-			}
-			if (MiriamType.PUBMED.equals(annotation.getDataType())) {
-				try {
-					Article article = pubmedParser.getPubmedArticleById(Integer.valueOf(annotation.getResource()));
-					result.put("article", article);
-				} catch (PubmedSearchException e) {
-					logger.error("Problem with accessing info about pubmed", e);
-				}
-			}
-			result.put("type", annotation.getDataType().name());
-			result.put("resource", annotation.getResource());
-			result.put("id", annotation.getId());
-			return result;
-		} else {
-			throw new InvalidArgumentException("invalid miriam data: " + annotation);
-		}
-	};
-
-	protected Map<String, Object> createAnnotation(AnnotationView annotation) {
-		Map<String, Object> result = new HashMap<>();
-		if (annotation != null && annotation.getType() != null) {
-			MiriamType type = MiriamType.getTypeByCommonName(annotation.getType());
-			result.put("link", annotation.getLink());
-			if (MiriamType.PUBMED.equals(type)) {
-				try {
-					Article article = pubmedParser.getPubmedArticleById(Integer.valueOf(annotation.getResource()));
-					result.put("article", article);
-				} catch (PubmedSearchException e) {
-					logger.error("Problem with accessing info about pubmed", e);
-				}
-			}
-			result.put("type", type);
-			result.put("resource", annotation.getResource());
-			result.put("id", annotation.getIdObject());
-		}
-		return result;
-	}
-
-	protected Map<String, Object> createAnnotation(Article article) {
-		Map<String, Object> result = new HashMap<>();
-		if (article != null) {
-			MiriamType type = MiriamType.PUBMED;
-			result.put("link", miriamConnector.getUrlString(new MiriamData(MiriamType.PUBMED, article.getId())));
-			result.put("article", article);
-			result.put("type", type);
-			result.put("resource", article.getId());
-		}
-		return result;
-	}
-
-	protected List<Map<String, Object>> createAnnotations(Collection<?> references) {
-		List<Map<String, Object>> result = new ArrayList<>();
-		for (Object miriamData : references) {
-			if (miriamData instanceof MiriamData) {
-				result.add(createAnnotation((MiriamData) miriamData));
-			} else if (miriamData instanceof AnnotationView) {
-				result.add(createAnnotation((AnnotationView) miriamData));
-			} else if (miriamData instanceof Article) {
-				result.add(createAnnotation((Article) miriamData));
-			} else {
-				throw new InvalidArgumentException();
-			}
-		}
-		return result;
-	}
-
-	protected List<Model> getModels(String projectId, String modelId, String token) throws SecurityException {
-		Model model = modelService.getLastModelByProjectId(projectId, userService.getToken(token));
-		List<Model> models = new ArrayList<>();
-
-		if (!modelId.equals("*")) {
-			for (String str : modelId.split(",")) {
-				models.add(model.getSubmodelById(Integer.valueOf(str)));
-			}
-		} else {
-			models.addAll(model.getSubmodels());
-			models.add(model);
-		}
-		return models;
-	}
-
-	/**
-	 * @return the modelService
-	 * @see #modelService
-	 */
-	public IModelService getModelService() {
-		return modelService;
-	}
-
-	/**
-	 * @param modelService
-	 *          the modelService to set
-	 * @see #modelService
-	 */
-	public void setModelService(IModelService modelService) {
-		this.modelService = modelService;
-	}
-
-	/**
-	 * @return the userService
-	 * @see #userService
-	 */
-	public IUserService getUserService() {
-		return userService;
-	}
-
-	/**
-	 * @param userService
-	 *          the userService to set
-	 * @see #userService
-	 */
-	public void setUserService(IUserService userService) {
-		this.userService = userService;
-	}
-
-	protected List<Map<String, Object>> prepareTargets(Collection<Target> targets, List<Model> models) {
-		List<Map<String, Object>> result = new ArrayList<>();
-		for (Target target : targets) {
-			result.add(prepareTarget(target, models));
-		}
-		result.sort(new Comparator<Map<String, Object>>() {
-
-			@Override
-			public int compare(Map<String, Object> o1, Map<String, Object> o2) {
-				List<?> targetedObjects1 = (List<?>) o1.get("targetElements");
-				List<?> targetedObjects2 = (List<?>) o2.get("targetElements");
-				Integer size1 = 0;
-				Integer size2 = 0;
-				if (targetedObjects1 != null) {
-					size1 = targetedObjects1.size();
-				}
-				if (targetedObjects2 != null) {
-					size2 = targetedObjects2.size();
-				}
-				return -size1.compareTo(size2);
-			}
-		});
-		return result;
-	}
-
-	protected Map<String, Object> prepareTarget(Target target, List<Model> models) {
-		Map<String, Object> result = new HashMap<>();
-		result.put("name", target.getName());
-		result.put("references", createAnnotations(target.getReferences()));
-		result.put("targetParticipants", createAnnotations(target.getGenes()));
-
-		List<Map<String, Object>> targetedObjects = new ArrayList<>();
-		for (Model model : models) {
-			for (BioEntity object : model.getBioEntities()) {
-				if (elementMatcher.elementMatch(target, object)) {
-					Map<String, Object> elementMapping = new HashMap<>();
-
-					elementMapping.put("id", object.getId());
-					elementMapping.put("type", getType(object));
-					elementMapping.put("modelId", model.getId());
-					targetedObjects.add(elementMapping);
-				}
-			}
-		}
-
-		result.put("targetElements", targetedObjects);
-
-		return result;
-	}
-
-	private String getType(BioEntity object) {
-		if (object instanceof Reaction) {
-			return ElementIdentifierType.REACTION.getJsName();
-		} else if (object instanceof Element) {
-			return ElementIdentifierType.ALIAS.getJsName();
-		} else {
-			throw new InvalidArgumentException("Unknown type of element " + object.getClass());
-		}
-	}
-
-	/**
-	 * @return the projectService
-	 * @see #projectService
-	 */
-	public IProjectService getProjectService() {
-		return projectService;
-	}
-
-	/**
-	 * @param projectService the projectService to set
-	 * @see #projectService
-	 */
-	public void setProjectService(IProjectService projectService) {
-		this.projectService = projectService;
-	}
-
-	protected IConverter getModelParser(String handlerClass) throws QueryException {
-		IConverter parser;
-		if (SbgnmlXmlConverter.class.getCanonicalName().equals(handlerClass)) {
-			parser = new SbgnmlXmlConverter();
-		} else if (CellDesignerXmlParser.class.getCanonicalName().equals(handlerClass)) {
-			parser = new CellDesignerXmlParser();
-		} else {
-			throw new QueryException("Unknown handlerClass: " + handlerClass);
-		}
-		return parser;
-	}
+  /**
+   * Default class logger.
+   */
+  private Logger logger = Logger.getLogger(BaseRestImpl.class);
+
+  @Autowired
+  private IModelService modelService;
+
+  @Autowired
+  private IProjectService projectService;
+
+  @Autowired
+  private IUserService userService;
+
+  @Autowired
+  private MiriamConnector miriamConnector;
+
+  @Autowired
+  private PubmedParser pubmedParser;
+
+  @Autowired
+  private ElementMatcher elementMatcher;
+
+  protected Map<String, Object> okStatus() {
+    Map<String, Object> result = new HashMap<>();
+    return result;
+  }
+
+  protected Map<String, Object> createMinifiedSearchResult(Object object) {
+    Map<String, Object> result = new HashMap<>();
+    if (object instanceof Element) {
+      result.put("type", ElementIdentifierType.ALIAS);
+      Element element = (Element) object;
+      result.put("id", element.getId());
+      result.put("modelId", element.getModel().getId());
+    } else if (object instanceof Reaction) {
+      result.put("type", ElementIdentifierType.REACTION);
+      Reaction element = (Reaction) object;
+      result.put("id", element.getId());
+      result.put("modelId", element.getModel().getId());
+
+    } else {
+      throw new InvalidStateException("Unknown type of result: " + object.getClass());
+    }
+    return result;
+  };
+
+  protected Map<String, Object> createAnnotation(MiriamData annotation) {
+    if (annotation != null && annotation.getDataType() != null) {
+      Map<String, Object> result = new HashMap<>();
+      if (annotation.getDataType().getUris().size() > 0) {
+        try {
+          result.put("link", miriamConnector.getUrlString(annotation));
+        } catch (Exception e) {
+          logger.error("Problem with miriam: " + annotation, e);
+        }
+      }
+      if (MiriamType.PUBMED.equals(annotation.getDataType())) {
+        try {
+          Article article = pubmedParser.getPubmedArticleById(Integer.valueOf(annotation.getResource()));
+          result.put("article", article);
+        } catch (PubmedSearchException e) {
+          logger.error("Problem with accessing info about pubmed", e);
+        }
+      }
+      result.put("type", annotation.getDataType().name());
+      result.put("resource", annotation.getResource());
+      result.put("id", annotation.getId());
+      return result;
+    } else {
+      throw new InvalidArgumentException("invalid miriam data: " + annotation);
+    }
+  };
+
+  protected Map<String, Object> createAnnotation(AnnotationView annotation) {
+    Map<String, Object> result = new HashMap<>();
+    if (annotation != null && annotation.getType() != null) {
+      MiriamType type = MiriamType.getTypeByCommonName(annotation.getType());
+      result.put("link", annotation.getLink());
+      if (MiriamType.PUBMED.equals(type)) {
+        try {
+          Article article = pubmedParser.getPubmedArticleById(Integer.valueOf(annotation.getResource()));
+          result.put("article", article);
+        } catch (PubmedSearchException e) {
+          logger.error("Problem with accessing info about pubmed", e);
+        }
+      }
+      result.put("type", type);
+      result.put("resource", annotation.getResource());
+      result.put("id", annotation.getIdObject());
+    }
+    return result;
+  }
+
+  protected Map<String, Object> createAnnotation(Article article) {
+    Map<String, Object> result = new HashMap<>();
+    if (article != null) {
+      MiriamType type = MiriamType.PUBMED;
+      result.put("link", miriamConnector.getUrlString(new MiriamData(MiriamType.PUBMED, article.getId())));
+      result.put("article", article);
+      result.put("type", type);
+      result.put("resource", article.getId());
+    }
+    return result;
+  }
+
+  protected List<Map<String, Object>> createAnnotations(Collection<?> references) {
+    List<Map<String, Object>> result = new ArrayList<>();
+    for (Object miriamData : references) {
+      if (miriamData instanceof MiriamData) {
+        result.add(createAnnotation((MiriamData) miriamData));
+      } else if (miriamData instanceof AnnotationView) {
+        result.add(createAnnotation((AnnotationView) miriamData));
+      } else if (miriamData instanceof Article) {
+        result.add(createAnnotation((Article) miriamData));
+      } else {
+        throw new InvalidArgumentException();
+      }
+    }
+    return result;
+  }
+
+  protected List<Model> getModels(String projectId, String modelId, String token) throws SecurityException {
+    Model model = modelService.getLastModelByProjectId(projectId, userService.getToken(token));
+    List<Model> models = new ArrayList<>();
+
+    if (!modelId.equals("*")) {
+      for (String str : modelId.split(",")) {
+        models.add(model.getSubmodelById(Integer.valueOf(str)));
+      }
+    } else {
+      models.addAll(model.getSubmodels());
+      models.add(model);
+    }
+    return models;
+  }
+
+  /**
+   * @return the modelService
+   * @see #modelService
+   */
+  public IModelService getModelService() {
+    return modelService;
+  }
+
+  /**
+   * @param modelService
+   *          the modelService to set
+   * @see #modelService
+   */
+  public void setModelService(IModelService modelService) {
+    this.modelService = modelService;
+  }
+
+  /**
+   * @return the userService
+   * @see #userService
+   */
+  public IUserService getUserService() {
+    return userService;
+  }
+
+  /**
+   * @param userService
+   *          the userService to set
+   * @see #userService
+   */
+  public void setUserService(IUserService userService) {
+    this.userService = userService;
+  }
+
+  protected List<Map<String, Object>> prepareTargets(Collection<Target> targets, List<Model> models) {
+    List<Map<String, Object>> result = new ArrayList<>();
+    for (Target target : targets) {
+      result.add(prepareTarget(target, models));
+    }
+    result.sort(new Comparator<Map<String, Object>>() {
+
+      @Override
+      public int compare(Map<String, Object> o1, Map<String, Object> o2) {
+        List<?> targetedObjects1 = (List<?>) o1.get("targetElements");
+        List<?> targetedObjects2 = (List<?>) o2.get("targetElements");
+        Integer size1 = 0;
+        Integer size2 = 0;
+        if (targetedObjects1 != null) {
+          size1 = targetedObjects1.size();
+        }
+        if (targetedObjects2 != null) {
+          size2 = targetedObjects2.size();
+        }
+        return -size1.compareTo(size2);
+      }
+    });
+    return result;
+  }
+
+  protected Map<String, Object> prepareTarget(Target target, List<Model> models) {
+    Map<String, Object> result = new HashMap<>();
+    result.put("name", target.getName());
+    result.put("references", createAnnotations(target.getReferences()));
+    result.put("targetParticipants", createAnnotations(target.getGenes()));
+
+    List<Map<String, Object>> targetedObjects = new ArrayList<>();
+    for (Model model : models) {
+      for (BioEntity object : model.getBioEntities()) {
+        if (elementMatcher.elementMatch(target, object)) {
+          Map<String, Object> elementMapping = new HashMap<>();
+
+          elementMapping.put("id", object.getId());
+          elementMapping.put("type", getType(object));
+          elementMapping.put("modelId", model.getId());
+          targetedObjects.add(elementMapping);
+        }
+      }
+    }
+
+    result.put("targetElements", targetedObjects);
+
+    return result;
+  }
+
+  private String getType(BioEntity object) {
+    if (object instanceof Reaction) {
+      return ElementIdentifierType.REACTION.getJsName();
+    } else if (object instanceof Element) {
+      return ElementIdentifierType.ALIAS.getJsName();
+    } else {
+      throw new InvalidArgumentException("Unknown type of element " + object.getClass());
+    }
+  }
+
+  /**
+   * @return the projectService
+   * @see #projectService
+   */
+  public IProjectService getProjectService() {
+    return projectService;
+  }
+
+  /**
+   * @param projectService
+   *          the projectService to set
+   * @see #projectService
+   */
+  public void setProjectService(IProjectService projectService) {
+    this.projectService = projectService;
+  }
+
+  protected IConverter getModelParser(String handlerClass) throws QueryException {
+    IConverter parser;
+    if (SbgnmlXmlConverter.class.getCanonicalName().equals(handlerClass)) {
+      parser = new SbgnmlXmlConverter();
+    } else if (CellDesignerXmlParser.class.getCanonicalName().equals(handlerClass)) {
+      parser = new CellDesignerXmlParser();
+    } else {
+      throw new QueryException("Unknown handlerClass: " + handlerClass);
+    }
+    return parser;
+  }
 
 }
diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/files/FileController.java b/rest-api/src/main/java/lcsb/mapviewer/api/files/FileController.java
new file mode 100644
index 0000000000000000000000000000000000000000..ed2a03cd09628619b266cd7b4965638285378e3f
--- /dev/null
+++ b/rest-api/src/main/java/lcsb/mapviewer/api/files/FileController.java
@@ -0,0 +1,59 @@
+package lcsb.mapviewer.api.files;
+
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.CookieValue;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import lcsb.mapviewer.api.BaseController;
+import lcsb.mapviewer.api.ObjectNotFoundException;
+import lcsb.mapviewer.common.Configuration;
+import lcsb.mapviewer.services.SecurityException;
+
+@RestController
+public class FileController extends BaseController {
+  /**
+   * Default class logger.
+   */
+  @SuppressWarnings("unused")
+  private Logger logger = Logger.getLogger(FileController.class);
+
+  @Autowired
+  private FileRestImpl fileRest;
+
+  @RequestMapping(value = "/files/", method = { RequestMethod.POST }, produces = { MediaType.APPLICATION_JSON_VALUE })
+  public Map<String, Object> createFile(//
+      @CookieValue(value = Configuration.AUTH_TOKEN) String token, //
+      @RequestParam(value = "filename") String filename, //
+      @RequestParam(value = "length") String length //
+  ) throws SecurityException {
+    return fileRest.createFile(token, filename, length);
+  }
+
+  @RequestMapping(value = "/files/{id}", method = { RequestMethod.GET }, produces = {
+      MediaType.APPLICATION_JSON_VALUE })
+  public Map<String, Object> getFile(//
+      @CookieValue(value = Configuration.AUTH_TOKEN) String token, //
+      @PathVariable(value = "id") String id //
+  ) throws SecurityException, ObjectNotFoundException {
+    return fileRest.getFile(token, id);
+  }
+
+  @RequestMapping(value = "/files/{id}:uploadContent", method = { RequestMethod.POST }, produces = {
+      MediaType.APPLICATION_JSON_VALUE })
+  public Map<String, Object> uploadContent(//
+      @CookieValue(value = Configuration.AUTH_TOKEN) String token, //
+      @PathVariable(value = "id") String id, //
+      @RequestBody byte[] data) throws SecurityException, ObjectNotFoundException {
+    return fileRest.uploadContent(token, id, data);
+  }
+
+}
\ No newline at end of file
diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/files/FileRestImpl.java b/rest-api/src/main/java/lcsb/mapviewer/api/files/FileRestImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..bb2ecfeae8a68b18bca61d7bacfc76c5b61cedb7
--- /dev/null
+++ b/rest-api/src/main/java/lcsb/mapviewer/api/files/FileRestImpl.java
@@ -0,0 +1,107 @@
+package lcsb.mapviewer.api.files;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.lang3.ArrayUtils;
+import org.hibernate.QueryException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+
+import lcsb.mapviewer.api.BaseRestImpl;
+import lcsb.mapviewer.api.ObjectNotFoundException;
+import lcsb.mapviewer.common.exception.InvalidStateException;
+import lcsb.mapviewer.model.cache.UploadedFileEntry;
+import lcsb.mapviewer.model.user.PrivilegeType;
+import lcsb.mapviewer.model.user.User;
+import lcsb.mapviewer.persist.dao.cache.UploadedFileEntryDao;
+import lcsb.mapviewer.services.SecurityException;
+import lcsb.mapviewer.services.interfaces.ILayoutService;
+
+@Transactional(value = "txManager")
+public class FileRestImpl extends BaseRestImpl {
+
+  @Autowired
+  private ILayoutService overlayService;
+
+  @Autowired
+  private UploadedFileEntryDao uploadedFileEntryDao;
+
+  public Map<String, Object> createFile(String token, String filename, String length) throws SecurityException {
+    User user = getUserService().getUserByToken(token);
+    if (!getUserService().userHasPrivilege(user, PrivilegeType.ADD_MAP)
+        && overlayService.getAvailableCustomLayoutsNumber(user) == 0) {
+      throw new SecurityException("Access denied");
+    }
+    UploadedFileEntry entry = new UploadedFileEntry();
+    entry.setOriginalFileName(filename);
+    entry.setFileContent(new byte[] {});
+    entry.setLength(Long.valueOf(length));
+    entry.setOwner(user);
+    uploadedFileEntryDao.add(entry);
+    try {
+      return getFile(token, entry.getId() + "");
+    } catch (ObjectNotFoundException e) {
+      throw new InvalidStateException(e);
+    }
+  }
+
+  public Map<String, Object> getFile(String token, String id) throws SecurityException, ObjectNotFoundException {
+    User user = getUserService().getUserByToken(token);
+    int fileId = Integer.valueOf(id);
+    UploadedFileEntry fileEntry = uploadedFileEntryDao.getById(fileId);
+    if (fileEntry == null) {
+      throw new ObjectNotFoundException("Object not found");
+    }
+    if (fileEntry.getOwner() == null) {
+      throw new SecurityException("Access denied");
+    }
+    if (!fileEntry.getOwner().getLogin().equals(user.getLogin())) {
+      throw new SecurityException("Access denied");
+    }
+    return serializeEntry(fileEntry);
+  }
+
+  private Map<String, Object> serializeEntry(UploadedFileEntry fileEntry) {
+    Map<String, Object> result = new HashMap<>();
+    result.put("id", fileEntry.getId());
+    result.put("filename", fileEntry.getOriginalFileName());
+    result.put("length", fileEntry.getLength());
+    result.put("owner", fileEntry.getOwner().getLogin());
+    result.put("uploadedDataLength", fileEntry.getFileContent().length);
+    return result;
+  }
+
+  public Map<String, Object> uploadContent(String token, String id, byte[] data) throws SecurityException, ObjectNotFoundException {
+    User user = getUserService().getUserByToken(token);
+    int fileId = Integer.valueOf(id);
+    UploadedFileEntry fileEntry = uploadedFileEntryDao.getById(fileId);
+    if (fileEntry == null) {
+      throw new ObjectNotFoundException("Object not found");
+    }
+    if (fileEntry.getOwner() == null) {
+      throw new SecurityException("Access denied");
+    }
+    if (!fileEntry.getOwner().getLogin().equals(user.getLogin())) {
+      throw new SecurityException("Access denied");
+    }
+    long missingByteLength = fileEntry.getLength() - fileEntry.getFileContent().length;
+    if (data.length > missingByteLength) {
+      throw new QueryException(
+          "Too many bytes sent. There are " + missingByteLength + " missing bytes, but " + data.length + " sent.");
+    }
+    byte[] newConent = ArrayUtils.addAll(fileEntry.getFileContent(), data);
+    fileEntry.setFileContent(newConent);
+    uploadedFileEntryDao.update(fileEntry);
+    return serializeEntry(fileEntry);
+  }
+
+  public UploadedFileEntryDao getUploadedFileEntryDao() {
+    return uploadedFileEntryDao;
+  }
+
+  public void setUploadedFileEntryDao(UploadedFileEntryDao uploadedFileEntryDao) {
+    this.uploadedFileEntryDao = uploadedFileEntryDao;
+  }
+
+}
diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/projects/ProjectRestImpl.java b/rest-api/src/main/java/lcsb/mapviewer/api/projects/ProjectRestImpl.java
index 6a50de4c1f70aa97abae624754c51e4b116e9f6a..802493819f983a542413cc68568e720a5cd34332 100644
--- a/rest-api/src/main/java/lcsb/mapviewer/api/projects/ProjectRestImpl.java
+++ b/rest-api/src/main/java/lcsb/mapviewer/api/projects/ProjectRestImpl.java
@@ -7,7 +7,6 @@ import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
@@ -38,16 +37,15 @@ import lcsb.mapviewer.commands.SetFixedHierarchyLevelCommand;
 import lcsb.mapviewer.commands.SubModelCommand;
 import lcsb.mapviewer.common.Configuration;
 import lcsb.mapviewer.common.exception.InvalidArgumentException;
-import lcsb.mapviewer.common.exception.NotImplementedException;
 import lcsb.mapviewer.converter.ConverterException;
 import lcsb.mapviewer.converter.IConverter;
 import lcsb.mapviewer.converter.graphics.AbstractImageGenerator.Params;
+import lcsb.mapviewer.converter.graphics.DrawingException;
+import lcsb.mapviewer.converter.graphics.ImageGenerators;
 import lcsb.mapviewer.converter.zip.ImageZipEntryFile;
 import lcsb.mapviewer.converter.zip.LayoutZipEntryFile;
 import lcsb.mapviewer.converter.zip.ModelZipEntryFile;
 import lcsb.mapviewer.converter.zip.ZipEntryFile;
-import lcsb.mapviewer.converter.graphics.DrawingException;
-import lcsb.mapviewer.converter.graphics.ImageGenerators;
 import lcsb.mapviewer.model.Project;
 import lcsb.mapviewer.model.cache.FileEntry;
 import lcsb.mapviewer.model.cache.UploadedFileEntry;
@@ -66,6 +64,7 @@ import lcsb.mapviewer.model.map.reaction.Reaction;
 import lcsb.mapviewer.model.map.species.Element;
 import lcsb.mapviewer.model.user.PrivilegeType;
 import lcsb.mapviewer.model.user.User;
+import lcsb.mapviewer.persist.dao.cache.UploadedFileEntryDao;
 import lcsb.mapviewer.services.SecurityException;
 import lcsb.mapviewer.services.interfaces.ILayoutService;
 import lcsb.mapviewer.services.interfaces.IProjectService;
@@ -105,6 +104,9 @@ public class ProjectRestImpl extends BaseRestImpl {
   @Autowired
   private OverviewImageViewFactory factory;
 
+  @Autowired
+  private UploadedFileEntryDao uploadedFileEntryDao;
+
   public ProjectMetaData getProject(String projectId, String token) throws SecurityException, ObjectNotFoundException {
     AuthenticationToken authenticationToken = getUserService().getToken(token);
     Project project = getProjectService().getProjectByProjectId(projectId, authenticationToken);
@@ -294,9 +296,10 @@ public class ProjectRestImpl extends BaseRestImpl {
 
     imageGenerator.generate(handlerClass, params, file.getAbsolutePath());
 
-    FileEntry entry = new UploadedFileEntry();
+    UploadedFileEntry entry = new UploadedFileEntry();
     entry.setOriginalFileName("map." + extension);
     entry.setFileContent(IOUtils.toByteArray(new FileInputStream(file)));
+    entry.setLength(entry.getFileContent().length);
     file.delete();
     return entry;
 
@@ -342,9 +345,10 @@ public class ProjectRestImpl extends BaseRestImpl {
 
     String fileExtension = parser.getFileExtension();
 
-    FileEntry entry = new UploadedFileEntry();
+    UploadedFileEntry entry = new UploadedFileEntry();
     entry.setOriginalFileName("model." + fileExtension);
     entry.setFileContent(IOUtils.toByteArray(is));
+    entry.setLength(entry.getFileContent().length);
     return entry;
 
   }
@@ -490,9 +494,16 @@ public class ProjectRestImpl extends BaseRestImpl {
     }
     CreateProjectParams params = new CreateProjectParams();
     String directory = path + "/../map_images/" + md5(projectId) + "/";
-    String fileContent = getFirstValue(data.get("file-content"));
-    if (fileContent == null) {
-      throw new QueryException("file-content is obligatory");
+    String fileId = getFirstValue(data.get("file-id"));
+    if (fileId == null) {
+      throw new QueryException("file-id is obligatory");
+    }
+    UploadedFileEntry file = uploadedFileEntryDao.getById(Integer.valueOf(fileId));
+    if (file == null) {
+      throw new QueryException("Invalid file id: " + fileId);
+    }
+    if (file.getOwner() == null || !file.getOwner().getLogin().equals(user.getLogin())) {
+      throw new SecurityException("Access denied to source file");
     }
     String parserClass = getFirstValue(data.get("parser"));
     if (parserClass == null) {
@@ -517,7 +528,7 @@ public class ProjectRestImpl extends BaseRestImpl {
     params.notifyEmail(getFirstValue(data.get("notify-email")));
     params.projectDir(directory);
     params.projectDisease(getFirstValue(data.get("disease")));
-    params.projectFile(new ByteArrayInputStream(fileContent.getBytes()));
+    params.projectFile(new ByteArrayInputStream(file.getFileContent()));
     params.projectId(projectId);
     params.projectName(getFirstValue(data.get("name")));
     params.projectOrganism(getFirstValue(data.get("organism")));
@@ -545,6 +556,7 @@ public class ProjectRestImpl extends BaseRestImpl {
       ZipEntryFile entry = null;
       String entryType = (String) data.get("zip-entries[" + fileIndex + "][_type]").get(0);
       String filename = (String) data.get("zip-entries[" + fileIndex + "][_filename]").get(0);
+      logger.debug(filename);
       if ("MAP".equalsIgnoreCase(entryType)) {
         String submodelTypeKey = "zip-entries[" + fileIndex + "][_data][type][id]";
         String rootKey = "zip-entries[" + fileIndex + "][_data][root]";
@@ -607,7 +619,7 @@ public class ProjectRestImpl extends BaseRestImpl {
       StringBuffer sb = new StringBuffer();
       for (int i = 0; i < mdbytes.length; i++) {
         // CHECKSTYLE:OFF
-        // this magic formula transforms int into hex value
+        // this magic formula transforms integer into hex value
         sb.append(Integer.toString((mdbytes[i] & 0xff) + 0x100, 16).substring(1));
         // CHECKSTYLE:ON
       }
@@ -627,4 +639,12 @@ public class ProjectRestImpl extends BaseRestImpl {
     return getProject(projectId, token);
   }
 
+  public UploadedFileEntryDao getUploadedFileEntryDao() {
+    return uploadedFileEntryDao;
+  }
+
+  public void setUploadedFileEntryDao(UploadedFileEntryDao uploadedFileEntryDao) {
+    this.uploadedFileEntryDao = uploadedFileEntryDao;
+  }
+
 }
diff --git a/rest-api/src/main/resources/applicationContext-rest.xml b/rest-api/src/main/resources/applicationContext-rest.xml
index 2642267ee9757e4925f78b5142c8022365264033..60c25537166dd4558c4ede64030b9bd3478c28a6 100644
--- a/rest-api/src/main/resources/applicationContext-rest.xml
+++ b/rest-api/src/main/resources/applicationContext-rest.xml
@@ -13,6 +13,8 @@
 	
 	<bean id="ConfigurationRestImpl" class="lcsb.mapviewer.api.configuration.ConfigurationRestImpl"/>
 
+	<bean id="FileRestImpl" class="lcsb.mapviewer.api.files.FileRestImpl"/>
+
 	<bean id="CommentRestImpl" class="lcsb.mapviewer.api.projects.comments.CommentRestImpl"/>
 	<bean id="ProjectRestImpl" class="lcsb.mapviewer.api.projects.ProjectRestImpl"/>
 	<bean id="ModelRestImpl" class="lcsb.mapviewer.api.projects.models.ModelRestImpl"/>
diff --git a/rest-api/src/test/java/lcsb/mapviewer/api/AllRestTests.java b/rest-api/src/test/java/lcsb/mapviewer/api/AllRestTests.java
index ced165d503c270a27bd8edf709870f2c55f60ac9..f1f28f0d09000c11c4f131a8fe0914fd212f95cd 100644
--- a/rest-api/src/test/java/lcsb/mapviewer/api/AllRestTests.java
+++ b/rest-api/src/test/java/lcsb/mapviewer/api/AllRestTests.java
@@ -5,15 +5,17 @@ import org.junit.runners.Suite;
 import org.junit.runners.Suite.SuiteClasses;
 
 import lcsb.mapviewer.api.configuration.AllConfigurationTests;
+import lcsb.mapviewer.api.files.AllFileTests;
 import lcsb.mapviewer.api.genomics.AllGenomicsTests;
 import lcsb.mapviewer.api.projects.AllProjectTests;
 import lcsb.mapviewer.api.users.AllUserTests;
 
 @RunWith(Suite.class)
 @SuiteClasses({ AllConfigurationTests.class, //
-		AllGenomicsTests.class, //
-		AllProjectTests.class, //
-		AllUserTests.class,//
+    AllFileTests.class, //
+    AllGenomicsTests.class, //
+    AllProjectTests.class, //
+    AllUserTests.class,//
 })
 public class AllRestTests {
 
diff --git a/rest-api/src/test/java/lcsb/mapviewer/api/RestTestFunctions.java b/rest-api/src/test/java/lcsb/mapviewer/api/RestTestFunctions.java
index a1a84dbd5fbca70097ba3fb8377466d6decb3cba..d6fec720437e9165e0018922504b098742eb1578 100644
--- a/rest-api/src/test/java/lcsb/mapviewer/api/RestTestFunctions.java
+++ b/rest-api/src/test/java/lcsb/mapviewer/api/RestTestFunctions.java
@@ -63,253 +63,253 @@ import lcsb.mapviewer.services.view.AuthenticationToken;
 
 @Transactional(value = "txManager")
 @Rollback(true)
-@ContextConfiguration(
-		locations = { "/applicationContext-persist.xml", "/applicationContext-annotation.xml", "/applicationContext-service.xml", "/applicationContext-rest.xml" })
+@ContextConfiguration(locations = { "/applicationContext-persist.xml", "/applicationContext-annotation.xml",
+    "/applicationContext-service.xml", "/applicationContext-rest.xml" })
 @RunWith(SpringJUnit4ClassRunner.class)
 public abstract class RestTestFunctions {
-	private Logger								logger	= Logger.getLogger(RestTestFunctions.class);
-
-	public double									EPSILON	= 1e-6;
-
-	@Autowired
-	protected PasswordEncoder			passwordEncoder;
-
-	@Autowired
-	protected IUserService				userService;
-
-	@Autowired
-	protected DbUtils							dbUtils;
-
-	protected AuthenticationToken	token;
-
-	protected AuthenticationToken	adminToken;
-
-	@Before
-	public void generalSetUp() {
-		dbUtils.setAutoFlush(false);
-
-		token = userService.login(Configuration.ANONYMOUS_LOGIN, null);
-
-		// assume that we have admin account with all the privileges
-		adminToken = userService.login("admin", "admin");
-
-	}
-
-	@After
-	public void generatTearDown() throws IOException {
-		File f = new File("map_images");
-		if (f.exists()) {
-			logger.info("Removing output test directory: " + f.getAbsolutePath());
-			FileUtils.deleteDirectory(f);
-		}
-
-	}
-
-	protected String readFile(String file) throws IOException {
-		StringBuilder stringBuilder = new StringBuilder();
-		BufferedReader reader = new BufferedReader(new FileReader(file));
-		try {
-			String line = null;
-			String ls = System.getProperty("line.separator");
-
-			while ((line = reader.readLine()) != null) {
-				stringBuilder.append(line);
-				stringBuilder.append(ls);
-			}
-		} finally {
-			reader.close();
-		}
-
-		return stringBuilder.toString();
-	}
-
-	protected Node getNodeFromXmlString(String text) throws InvalidXmlSchemaException {
-		InputSource is = new InputSource();
-		is.setCharacterStream(new StringReader(text));
-		return getXmlDocumentFromInputSource(is).getChildNodes().item(0);
-	}
-
-	protected Document getXmlDocumentFromFile(String fileName) throws InvalidXmlSchemaException, IOException {
-		File file = new File(fileName);
-		InputStream inputStream = new FileInputStream(file);
-		Reader reader = null;
-		try {
-			reader = new InputStreamReader(inputStream, "UTF-8");
-			InputSource is = new InputSource(reader);
-
-			Document result = getXmlDocumentFromInputSource(is);
-			inputStream.close();
-			return result;
-		} catch (UnsupportedEncodingException e) {
-			// TODO Auto-generated catch block
-			e.printStackTrace();
-		}
-		return null;
-	}
-
-	protected Document getXmlDocumentFromInputSource(InputSource stream) throws InvalidXmlSchemaException {
-		DocumentBuilder db;
-		try {
-			db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
-		} catch (ParserConfigurationException e) {
-			throw new InvalidXmlSchemaException("Problem with xml parser");
-		}
-		Document doc = null;
-		try {
-			doc = db.parse(stream);
-		} catch (SAXException e) {
-			logger.error(e);
-		} catch (IOException e) {
-			logger.error(e);
-		}
-		return doc;
-	}
-
-	private static Map<String, Model> models = new HashMap<String, Model>();
-
-	protected Model getModelForFile(String fileName, boolean fromCache) throws Exception {
-		Model result = null;
-		if (!fromCache) {
-			logger.debug("File without cache: " + fileName);
-			result = getModelForFile(fileName);
-		} else {
-			result = RestTestFunctions.models.get(fileName);
-			if (result == null) {
-				logger.debug("File to cache: " + fileName);
-
-				result = getModelForFile(fileName);
-				RestTestFunctions.models.put(fileName, result);
-			}
-		}
-		return result;
-	}
-
-	private Model getModelForFile(String fileName) throws InvalidInputDataExecption, IOException {
-		if (fileName.endsWith("zip")) {
-			ComplexZipConverter  parser = new ComplexZipConverter(CellDesignerXmlParser.class);
-			ComplexZipConverterParams complexParams;
-			complexParams = new ComplexZipConverterParams().zipFile(fileName);
-			ZipEntryFile entry1 = new ModelZipEntryFile("main.xml", "main", true, false, SubmodelType.UNKNOWN);
-			ZipEntryFile entry2 = new ModelZipEntryFile("submaps/s1.xml", "s1", false, false, SubmodelType.UNKNOWN);
-			ZipEntryFile entry3 = new ModelZipEntryFile("submaps/s2.xml", "s2", false, false, SubmodelType.UNKNOWN);
-			ZipEntryFile entry4 = new ModelZipEntryFile("submaps/s3.xml", "s3", false, false, SubmodelType.UNKNOWN);
-			ZipEntryFile entry5 = new ModelZipEntryFile("submaps/mapping.xml", "mapping", false, true, SubmodelType.UNKNOWN);
-			complexParams.entry(entry1);
-			complexParams.entry(entry2);
-			complexParams.entry(entry3);
-			complexParams.entry(entry4);
-			complexParams.entry(entry5);
-
-			Model model =parser.createModel(complexParams);
-			model.setTileSize(256);
-			for (ModelSubmodelConnection connection: model.getSubmodelConnections()) {
-				connection.getSubmodel().setTileSize(256);
-			}
-			model.setProject(new Project());
-			return model;
-
-		} else {
-			Model model = new CellDesignerXmlParser().createModel(new ConverterParams().filename(fileName));
-			model.setTileSize(256);
-			model.setProject(new Project());
-			return model;
-		}
-	}
-
-	protected String createTmpFileName() {
-		try {
-			File f = File.createTempFile("prefix", ".txt");
-			String filename = f.getName();
-			f.delete();
-			return filename;
-		} catch (IOException e) {
-			e.printStackTrace();
-			return null;
-		}
-	}
-
-	protected String nodeToString(Node node) {
-		return nodeToString(node, false);
-	}
-
-	protected String nodeToString(Node node, boolean includeHeadNode) {
-		if (node == null)
-			return null;
-		StringWriter sw = new StringWriter();
-		try {
-			Transformer t = TransformerFactory.newInstance().newTransformer();
-			t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
-			t.setOutputProperty(OutputKeys.INDENT, "yes");
-			t.setOutputProperty(OutputKeys.METHOD, "xml");
-
-			NodeList list = node.getChildNodes();
-			for (int i = 0; i < list.getLength(); i++) {
-				Node element = list.item(i);
-				t.transform(new DOMSource(element), new StreamResult(sw));
-			}
-		} catch (TransformerException te) {
-			logger.debug("nodeToString Transformer Exception");
-		}
-		if (includeHeadNode) {
-			return "<" + node.getNodeName() + ">" + sw.toString() + "</" + node.getNodeName() + ">";
-		}
-		return sw.toString();
-	}
-
-	protected boolean equalFiles(String fileA, String fileB) throws IOException {
-		int BLOCK_SIZE = 65536;
-		FileInputStream inputStreamA = new FileInputStream(fileA);
-		FileInputStream inputStreamB = new FileInputStream(fileB);
-		// vary BLOCK_SIZE to suit yourself.
-		// it should probably a factor or multiple of the size of a disk
-		// sector/cluster.
-		// Note that your max heap size may need to be adjused
-		// if you have a very big block size or lots of these comparators.
-
-		// assume inputStreamA and inputStreamB are streams from your two files.
-		byte[] streamABlock = new byte[BLOCK_SIZE];
-		byte[] streamBBlock = new byte[BLOCK_SIZE];
-		boolean match = true;
-		int bytesReadA = 0;
-		int bytesReadB = 0;
-		do {
-			bytesReadA = inputStreamA.read(streamABlock);
-			bytesReadB = inputStreamB.read(streamBBlock);
-			match = ((bytesReadA == bytesReadB) && Arrays.equals(streamABlock, streamBBlock));
-		} while (match && (bytesReadA > -1));
-		inputStreamA.close();
-		inputStreamB.close();
-		return match;
-	}
-
-	public File createTempDirectory() throws IOException {
-		final File temp;
-
-		temp = File.createTempFile("temp", Long.toString(System.nanoTime()));
-
-		if (!(temp.delete())) {
-			throw new IOException("Could not delete temp file: " + temp.getAbsolutePath());
-		}
-
-		if (!(temp.mkdir())) {
-			throw new IOException("Could not create temp directory: " + temp.getAbsolutePath());
-		}
-
-		return (temp);
-	}
-
-	protected String getWebpage(String accessUrl) throws IOException {
-		String inputLine;
-		StringBuilder tmp = new StringBuilder();
-		URL url = new URL(accessUrl);
-		URLConnection urlConn = url.openConnection();
-		BufferedReader in = new BufferedReader(new InputStreamReader(urlConn.getInputStream()));
-
-		while ((inputLine = in.readLine()) != null) {
-			tmp.append(inputLine);
-		}
-		in.close();
-		return tmp.toString();
-	}
+  private Logger logger = Logger.getLogger(RestTestFunctions.class);
+
+  public double EPSILON = 1e-6;
+
+  @Autowired
+  protected PasswordEncoder passwordEncoder;
+
+  @Autowired
+  protected IUserService userService;
+
+  @Autowired
+  protected DbUtils dbUtils;
+
+  protected AuthenticationToken token;
+
+  protected AuthenticationToken adminToken;
+
+  @Before
+  public void generalSetUp() {
+    dbUtils.setAutoFlush(false);
+
+    token = userService.login(Configuration.ANONYMOUS_LOGIN, null);
+
+    // assume that we have admin account with all the privileges
+    adminToken = userService.login("admin", "admin");
+
+  }
+
+  @After
+  public void generatTearDown() throws IOException {
+    File f = new File("map_images");
+    if (f.exists()) {
+      logger.info("Removing output test directory: " + f.getAbsolutePath());
+      FileUtils.deleteDirectory(f);
+    }
+
+  }
+
+  protected String readFile(String file) throws IOException {
+    StringBuilder stringBuilder = new StringBuilder();
+    BufferedReader reader = new BufferedReader(new FileReader(file));
+    try {
+      String line = null;
+      String ls = System.getProperty("line.separator");
+
+      while ((line = reader.readLine()) != null) {
+        stringBuilder.append(line);
+        stringBuilder.append(ls);
+      }
+    } finally {
+      reader.close();
+    }
+
+    return stringBuilder.toString();
+  }
+
+  protected Node getNodeFromXmlString(String text) throws InvalidXmlSchemaException {
+    InputSource is = new InputSource();
+    is.setCharacterStream(new StringReader(text));
+    return getXmlDocumentFromInputSource(is).getChildNodes().item(0);
+  }
+
+  protected Document getXmlDocumentFromFile(String fileName) throws InvalidXmlSchemaException, IOException {
+    File file = new File(fileName);
+    InputStream inputStream = new FileInputStream(file);
+    Reader reader = null;
+    try {
+      reader = new InputStreamReader(inputStream, "UTF-8");
+      InputSource is = new InputSource(reader);
+
+      Document result = getXmlDocumentFromInputSource(is);
+      inputStream.close();
+      return result;
+    } catch (UnsupportedEncodingException e) {
+      // TODO Auto-generated catch block
+      e.printStackTrace();
+    }
+    return null;
+  }
+
+  protected Document getXmlDocumentFromInputSource(InputSource stream) throws InvalidXmlSchemaException {
+    DocumentBuilder db;
+    try {
+      db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+    } catch (ParserConfigurationException e) {
+      throw new InvalidXmlSchemaException("Problem with xml parser");
+    }
+    Document doc = null;
+    try {
+      doc = db.parse(stream);
+    } catch (SAXException e) {
+      logger.error(e);
+    } catch (IOException e) {
+      logger.error(e);
+    }
+    return doc;
+  }
+
+  private static Map<String, Model> models = new HashMap<String, Model>();
+
+  protected Model getModelForFile(String fileName, boolean fromCache) throws Exception {
+    Model result = null;
+    if (!fromCache) {
+      logger.debug("File without cache: " + fileName);
+      result = getModelForFile(fileName);
+    } else {
+      result = RestTestFunctions.models.get(fileName);
+      if (result == null) {
+        logger.debug("File to cache: " + fileName);
+
+        result = getModelForFile(fileName);
+        RestTestFunctions.models.put(fileName, result);
+      }
+    }
+    return result;
+  }
+
+  private Model getModelForFile(String fileName) throws InvalidInputDataExecption, IOException {
+    if (fileName.endsWith("zip")) {
+      ComplexZipConverter parser = new ComplexZipConverter(CellDesignerXmlParser.class);
+      ComplexZipConverterParams complexParams;
+      complexParams = new ComplexZipConverterParams().zipFile(fileName);
+      ZipEntryFile entry1 = new ModelZipEntryFile("main.xml", "main", true, false, SubmodelType.UNKNOWN);
+      ZipEntryFile entry2 = new ModelZipEntryFile("submaps/s1.xml", "s1", false, false, SubmodelType.UNKNOWN);
+      ZipEntryFile entry3 = new ModelZipEntryFile("submaps/s2.xml", "s2", false, false, SubmodelType.UNKNOWN);
+      ZipEntryFile entry4 = new ModelZipEntryFile("submaps/s3.xml", "s3", false, false, SubmodelType.UNKNOWN);
+      ZipEntryFile entry5 = new ModelZipEntryFile("submaps/mapping.xml", "mapping", false, true, SubmodelType.UNKNOWN);
+      complexParams.entry(entry1);
+      complexParams.entry(entry2);
+      complexParams.entry(entry3);
+      complexParams.entry(entry4);
+      complexParams.entry(entry5);
+
+      Model model = parser.createModel(complexParams);
+      model.setTileSize(256);
+      for (ModelSubmodelConnection connection : model.getSubmodelConnections()) {
+        connection.getSubmodel().setTileSize(256);
+      }
+      model.setProject(new Project());
+      return model;
+
+    } else {
+      Model model = new CellDesignerXmlParser().createModel(new ConverterParams().filename(fileName));
+      model.setTileSize(256);
+      model.setProject(new Project());
+      return model;
+    }
+  }
+
+  protected String createTmpFileName() {
+    try {
+      File f = File.createTempFile("prefix", ".txt");
+      String filename = f.getName();
+      f.delete();
+      return filename;
+    } catch (IOException e) {
+      e.printStackTrace();
+      return null;
+    }
+  }
+
+  protected String nodeToString(Node node) {
+    return nodeToString(node, false);
+  }
+
+  protected String nodeToString(Node node, boolean includeHeadNode) {
+    if (node == null)
+      return null;
+    StringWriter sw = new StringWriter();
+    try {
+      Transformer t = TransformerFactory.newInstance().newTransformer();
+      t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
+      t.setOutputProperty(OutputKeys.INDENT, "yes");
+      t.setOutputProperty(OutputKeys.METHOD, "xml");
+
+      NodeList list = node.getChildNodes();
+      for (int i = 0; i < list.getLength(); i++) {
+        Node element = list.item(i);
+        t.transform(new DOMSource(element), new StreamResult(sw));
+      }
+    } catch (TransformerException te) {
+      logger.debug("nodeToString Transformer Exception");
+    }
+    if (includeHeadNode) {
+      return "<" + node.getNodeName() + ">" + sw.toString() + "</" + node.getNodeName() + ">";
+    }
+    return sw.toString();
+  }
+
+  protected boolean equalFiles(String fileA, String fileB) throws IOException {
+    int BLOCK_SIZE = 65536;
+    FileInputStream inputStreamA = new FileInputStream(fileA);
+    FileInputStream inputStreamB = new FileInputStream(fileB);
+    // vary BLOCK_SIZE to suit yourself.
+    // it should probably a factor or multiple of the size of a disk
+    // sector/cluster.
+    // Note that your max heap size may need to be adjused
+    // if you have a very big block size or lots of these comparators.
+
+    // assume inputStreamA and inputStreamB are streams from your two files.
+    byte[] streamABlock = new byte[BLOCK_SIZE];
+    byte[] streamBBlock = new byte[BLOCK_SIZE];
+    boolean match = true;
+    int bytesReadA = 0;
+    int bytesReadB = 0;
+    do {
+      bytesReadA = inputStreamA.read(streamABlock);
+      bytesReadB = inputStreamB.read(streamBBlock);
+      match = ((bytesReadA == bytesReadB) && Arrays.equals(streamABlock, streamBBlock));
+    } while (match && (bytesReadA > -1));
+    inputStreamA.close();
+    inputStreamB.close();
+    return match;
+  }
+
+  public File createTempDirectory() throws IOException {
+    final File temp;
+
+    temp = File.createTempFile("temp", Long.toString(System.nanoTime()));
+
+    if (!(temp.delete())) {
+      throw new IOException("Could not delete temp file: " + temp.getAbsolutePath());
+    }
+
+    if (!(temp.mkdir())) {
+      throw new IOException("Could not create temp directory: " + temp.getAbsolutePath());
+    }
+
+    return (temp);
+  }
+
+  protected String getWebpage(String accessUrl) throws IOException {
+    String inputLine;
+    StringBuilder tmp = new StringBuilder();
+    URL url = new URL(accessUrl);
+    URLConnection urlConn = url.openConnection();
+    BufferedReader in = new BufferedReader(new InputStreamReader(urlConn.getInputStream()));
+
+    while ((inputLine = in.readLine()) != null) {
+      tmp.append(inputLine);
+    }
+    in.close();
+    return tmp.toString();
+  }
 
 }
diff --git a/rest-api/src/test/java/lcsb/mapviewer/api/files/AllFileTests.java b/rest-api/src/test/java/lcsb/mapviewer/api/files/AllFileTests.java
new file mode 100644
index 0000000000000000000000000000000000000000..25e1d4be319489304287bbc14578a89ea38d1aa6
--- /dev/null
+++ b/rest-api/src/test/java/lcsb/mapviewer/api/files/AllFileTests.java
@@ -0,0 +1,11 @@
+package lcsb.mapviewer.api.files;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+import org.junit.runners.Suite.SuiteClasses;
+
+@RunWith(Suite.class)
+@SuiteClasses({ FileRestImplTest.class })
+public class AllFileTests {
+
+}
diff --git a/rest-api/src/test/java/lcsb/mapviewer/api/files/FileRestImplTest.java b/rest-api/src/test/java/lcsb/mapviewer/api/files/FileRestImplTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..69ef990fdfc1f6cef0698f94e0b37d4e38a48de1
--- /dev/null
+++ b/rest-api/src/test/java/lcsb/mapviewer/api/files/FileRestImplTest.java
@@ -0,0 +1,80 @@
+package lcsb.mapviewer.api.files;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.Map;
+
+import org.apache.commons.lang3.ArrayUtils;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import lcsb.mapviewer.api.RestTestFunctions;
+import lcsb.mapviewer.model.cache.UploadedFileEntry;
+import lcsb.mapviewer.persist.dao.cache.UploadedFileEntryDao;
+
+public class FileRestImplTest extends RestTestFunctions {
+
+  @Autowired
+  UploadedFileEntryDao uploadedFileEntryDao;
+
+  @Autowired
+  FileRestImpl fileRestImpl;
+
+  @Test(expected = lcsb.mapviewer.services.SecurityException.class)
+  public void testCreateFileWithoutPrivilege() throws Exception {
+    fileRestImpl.createFile(token.getId(), "test.txt", "100");
+  }
+
+  @Test
+  public void testCreateFile() throws Exception {
+    Map<String, Object> result = fileRestImpl.createFile(adminToken.getId(), "test.txt", "100");
+    assertNotNull(result);
+    int id = (Integer) result.get("id");
+    UploadedFileEntry file = uploadedFileEntryDao.getById(id);
+    assertNotNull(file);
+    assertEquals(100, file.getLength());
+    assertEquals(0, file.getFileContent().length);
+    uploadedFileEntryDao.delete(file);
+  }
+
+  @Test
+  public void testUploadContent() throws Exception {
+    byte[] dataChunk = new byte[] { 105, 103 };
+    byte[] dataChunk2 = new byte[] { 32, 73 };
+    byte[] dataChunkMerged = ArrayUtils.addAll(dataChunk, dataChunk2);
+    Map<String, Object> result = fileRestImpl.createFile(adminToken.getId(), "test.txt", "100");
+    int id = (Integer) result.get("id");
+    fileRestImpl.uploadContent(adminToken.getId(), id + "", dataChunk);
+
+    UploadedFileEntry file = uploadedFileEntryDao.getById(id);
+    assertEquals(100, file.getLength());
+    assertEquals(2, file.getFileContent().length);
+    assertArrayEquals(dataChunk, file.getFileContent());
+
+    fileRestImpl.uploadContent(adminToken.getId(), id + "", dataChunk2);
+
+    assertEquals(100, file.getLength());
+    assertEquals(4, file.getFileContent().length);
+    assertArrayEquals(dataChunkMerged, file.getFileContent());
+
+    uploadedFileEntryDao.delete(file);
+  }
+
+  @Test
+  public void testUploadInvalidContent() throws Exception {
+    byte[] dataChunk = new byte[100];
+    Map<String, Object> result = fileRestImpl.createFile(adminToken.getId(), "test.txt", "100");
+    int id = (Integer) result.get("id");
+
+    try {
+      fileRestImpl.uploadContent(adminToken.getId(), id + "", dataChunk);
+    } finally {
+      uploadedFileEntryDao.getById(id);
+      UploadedFileEntry file = uploadedFileEntryDao.getById(id);
+      uploadedFileEntryDao.delete(file);
+    }
+  }
+
+}
diff --git a/service/src/main/java/lcsb/mapviewer/services/SecurityException.java b/service/src/main/java/lcsb/mapviewer/services/SecurityException.java
index dae25a98227340193b74fa7271e164133807eced..de076a2bbccfc5aa77a04bd4e0b5af5a3822195e 100644
--- a/service/src/main/java/lcsb/mapviewer/services/SecurityException.java
+++ b/service/src/main/java/lcsb/mapviewer/services/SecurityException.java
@@ -2,13 +2,17 @@ package lcsb.mapviewer.services;
 
 public class SecurityException extends Exception {
 
-	/**
-	 * 
-	 */
-	private static final long serialVersionUID = 1L;
-
-	public SecurityException(String message) {
-		super(message);
-	}
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 1L;
+
+  public SecurityException(String message) {
+    super(message);
+  }
+
+  public SecurityException() {
+    super();
+  }
 
 }
diff --git a/service/src/main/java/lcsb/mapviewer/services/impl/LayoutService.java b/service/src/main/java/lcsb/mapviewer/services/impl/LayoutService.java
index 646931a61237fc94f527d9a6b2a79774adba940f..91f445f061ea5ba68763b3be6290abd44137eab3 100644
--- a/service/src/main/java/lcsb/mapviewer/services/impl/LayoutService.java
+++ b/service/src/main/java/lcsb/mapviewer/services/impl/LayoutService.java
@@ -351,6 +351,8 @@ public class LayoutService implements ILayoutService {
 		UploadedFileEntry fileEntry = new UploadedFileEntry();
 		fileEntry.setFileContent(IOUtils.toByteArray(params.getColorInputStream()));
 		fileEntry.setOriginalFileName(params.getLayoutFileName());
+        fileEntry.setLength(fileEntry.getFileContent().length);
+        fileEntry.setOwner(params.getUser());
 		topLayout.setInputData(fileEntry);
 		topLayout.setDescription(params.getDescription());
 		params.getModel().addLayout(topLayout);
@@ -511,6 +513,8 @@ public class LayoutService implements ILayoutService {
 		UploadedFileEntry fileEntry = new UploadedFileEntry();
 		fileEntry.setFileContent(IOUtils.toByteArray(params.getColorInputStream()));
 		fileEntry.setOriginalFileName(params.getLayoutFileName());
+        fileEntry.setLength(fileEntry.getFileContent().length);
+        fileEntry.setOwner(params.getUser());
 		topLayout.setInputData(fileEntry);
 		topLayout.setDescription(params.getDescription());
 		params.getModel().addLayout(topLayout);
diff --git a/service/src/main/java/lcsb/mapviewer/services/impl/ProjectService.java b/service/src/main/java/lcsb/mapviewer/services/impl/ProjectService.java
index db91fe0556f28ab1fa735cf66073fbd4176f376d..f50002b773c058e6d125eea78c3841aa4ee1d77f 100644
--- a/service/src/main/java/lcsb/mapviewer/services/impl/ProjectService.java
+++ b/service/src/main/java/lcsb/mapviewer/services/impl/ProjectService.java
@@ -119,1455 +119,1481 @@ import lcsb.mapviewer.services.view.ProjectViewFactory;
 @Transactional(value = "txManager")
 public class ProjectService implements IProjectService {
 
-	/**
-	 * Size of the artifitial buffer that will be released when
-	 * {@link OutOfMemoryError} is thrown to gain some free memory and report
-	 * problem.
-	 */
-	private static final int			OUT_OF_MEMORY_BACKUP_BUFFER_SIZE = 10000;
-
-	/**
-	 * How much time (out of 1.00) is used for creation of the data from file.
-	 */
-	private static final double		CREATION_OF_DATA								 = 0.50;
-
-	/**
-	 * How much time (out of 1.00) is used for upploading of the data from file.
-	 */
-	private static final double		UPLOAD_OF_DATA									 = 0.50;
-
-	/**
-	 * Default class logger.
-	 */
-	private Logger								logger													 = Logger.getLogger(ProjectService.class);
-
-	/**
-	 * Data access object for projects.
-	 */
-	@Autowired
-	private ProjectDao						projectDao;
-
-	/**
-	 * Data access object for models.
-	 */
-	@Autowired
-	private ModelDao							modelDao;
-
-	/**
-	 * Data access object for users.
-	 */
-	@Autowired
-	private UserDao								userDao;
-
-	/**
-	 * Service that allows to access and manage models.
-	 */
-	@Autowired
-	private IModelService					modelService;
-
-	/**
-	 * Service that allows to access and manage comments.
-	 */
-	@Autowired
-	private ICommentService				commentService;
-
-	/**
-	 * Service used to access logs.
-	 * 
-	 * @see ILogService
-	 */
-	@Autowired
-	private ILogService						logService;
-
-	/**
-	 * Service that manages and gives access to configuration parameters.
-	 */
-	@Autowired
-	private IConfigurationService	configurationService;
-
-	/**
-	 * Services that manages and gives access to user information.
-	 */
-	@Autowired
-	private IUserService					userService;
-
-	/**
-	 * Services that accessa data about chemicals.
-	 */
-	@Autowired
-	private IChemicalService			chemicalService;
-
-	/**
-	 * Services that accessa data about drugs.
-	 */
-	@Autowired
-	private IDrugService					drugService;
-
-	/**
-	 * Services that accessa data about mirna.
-	 */
-	@Autowired
-	private IMiRNAService					mirnaService;
-
-	/**
-	 * Service that manages data mining information.
-	 */
-	@Autowired
-	private IDataMiningService		dataMiningService;
-
-	/**
-	 * Data access object for comments.
-	 */
-	@Autowired
-	private CommentDao						commentDao;
-
-	/**
-	 * Service that provides password encoding.
-	 */
-	@Autowired
-	private PasswordEncoder				passwordEncoder;
-
-	/**
-	 * Module that allows to annotate maps.
-	 */
-	@Autowired
-	private ModelAnnotator				modelAnnotator;
-
-	/**
-	 * Utils that help to manage the sessions in custom multithreaded
-	 * implementation.
-	 */
-	@Autowired
-	private DbUtils								dbUtils;
-
-	/**
-	 * Factory object for {@link ProjectView} elements.
-	 */
-	@Autowired
-	private ProjectViewFactory		projectViewFactory;
-
-	/**
-	 * Access point and parser for the online ctd database.
-	 */
-	@Autowired
-	private MeSHParser						meshParser;
-
-	/**
-	 * Access point and parser for the online ctd database.
-	 */
-	@Autowired
-	private TaxonomyBackend				taxonomyBackend;
-
-	/**
-	 * Class that helps to generate images for google maps API.
-	 */
-	private MapGenerator					generator												 = new MapGenerator();
-
-	@Override
-	public Project getProjectByProjectId(String name, AuthenticationToken token) throws UserAccessException {
-		Project result = projectDao.getProjectByProjectId(name);
-		if (result == null) {
-			return result;
-		}
-		if (userService.userHasPrivilege(token, PrivilegeType.VIEW_PROJECT, result)) {
-			return result;
-		} else if (userService.userHasPrivilege(token, PrivilegeType.ADD_MAP)) {
-			return result;
-		}
-		throw new UserAccessException("User cannot access project");
-	}
-
-	@Override
-	public boolean projectExists(String projectName) {
-		if (projectName == null || projectName.equals("")) {
-			return false;
-		}
-		return projectDao.isProjectExistsByName(projectName);
-	}
-
-	@Override
-	public List<Project> getAllProjects(AuthenticationToken token) {
-		List<Project> projects = projectDao.getAll();
-		if (userService.userHasPrivilege(token, PrivilegeType.ADD_MAP)) {
-			return projects;
-		}
-		List<Project> result = new ArrayList<>();
-		for (Project project : projects) {
-			if (userService.userHasPrivilege(token, PrivilegeType.VIEW_PROJECT, project)) {
-				result.add(project);
-			}
-		}
-		return result;
-	}
-
-	@Override
-	public List<ProjectView> getAllProjectViews(AuthenticationToken token) {
-		List<ProjectView> result = new ArrayList<>();
-		List<Project> projects = getAllProjects(token);
-		for (Project project : projects) {
-			result.add(projectViewFactory.create(project));
-		}
-		return result;
-	}
-
-	@Override
-	public void updateProject(ProjectView selectedProject) {
-		Project project = projectDao.getById(selectedProject.getIdObject());
-		project.setProjectId(selectedProject.getProjectId());
-		project.setName(selectedProject.getProjectName());
-		project.setVersion(selectedProject.getVersion());
-		project.setNotifyEmail(selectedProject.getNotifyEmail());
-		MiriamData disease = null;
-		MiriamData organism = null;
-		if (selectedProject.getNewDiseaseName() != null && !selectedProject.getNewDiseaseName().isEmpty()) {
-			disease = new MiriamData(MiriamType.MESH_2012, selectedProject.getNewDiseaseName());
-		}
-		if (selectedProject.getNewOrganismName() != null && !selectedProject.getNewOrganismName().isEmpty()) {
-			organism = new MiriamData(MiriamType.TAXONOMY, selectedProject.getNewOrganismName());
-		}
-		try {
-			if (meshParser.isValidMeshId(disease)) {
-				project.setDisease(disease);
-			} else {
-				project.setDisease(null);
-				selectedProject.setNewDiseaseName(null);
-			}
-		} catch (AnnotatorException e) {
-			logger.error("Problem with accessing mesh", e);
-			project.setDisease(null);
-			selectedProject.setNewDiseaseName(null);
-		}
-		try {
-			if (taxonomyBackend.getNameForTaxonomy(organism) != null) {
-				project.setOrganism(organism);
-			} else {
-				project.setOrganism(null);
-				selectedProject.setNewOrganismName(null);
-			}
-		} catch (TaxonomySearchException e) {
-			logger.error("Problem with accessing taxonomy db", e);
-			project.setOrganism(null);
-			selectedProject.setNewOrganismName(null);
-		}
-		for (ModelData model : project.getModels()) {
-			if (model.getId().equals(selectedProject.getModelId())) {
-				modelService.updateModel(model, selectedProject);
-			}
-		}
-		projectDao.update(project);
-	}
-
-	@Override
-	public void removeProject(ProjectView selectedProject, String homeDir, boolean async, AuthenticationToken token) throws UserAccessException {
-		Project project = projectDao.getById(selectedProject.getIdObject());
-		removeProject(project, homeDir, async, token);
-	}
-
-	/**
-	 * Removes all types of privileges from every user to the project given in the
-	 * parameter.
-	 * 
-	 * @param project
-	 *          from which project we remove privileges
-	 */
-	private void removePrivilegesForProject(Project project) {
-		for (PrivilegeType type : PrivilegeType.values()) {
-			if (type.getPrivilegeObjectType() == Project.class) {
-				userService.dropPrivilegesForObjectType(type, project.getId());
-			}
-		}
-	}
-
-	@Override
-	public ProjectView getProjectViewByProjectId(String name, AuthenticationToken token) throws UserAccessException {
-		Project project = getProjectByProjectId(name, token);
-		return projectViewFactory.create(project);
-	}
-
-	@Override
-	public void removeProject(final Project p, final String dir, final boolean async, AuthenticationToken token) throws UserAccessException {
-		if (!userService.userHasPrivilege(userService.getUserByToken(token), PrivilegeType.PROJECT_MANAGEMENT)) {
-			throw new UserAccessException("User cannot remove project");
-		}
-
-		final String homeDir;
-		if (dir != null) {
-			if (p.getDirectory() != null) {
-				homeDir = dir + "/../map_images/" + p.getDirectory() + "/";
-			} else {
-				homeDir = dir + "/../map_images/";
-			}
-		} else {
-			if (p.getDirectory() != null) {
-				homeDir = p.getDirectory() + "/";
-			} else {
-				homeDir = null;
-			}
-		}
-		removePrivilegesForProject(p);
-		updateProjectStatus(p, ProjectStatus.REMOVING, 0, new CreateProjectParams());
-		Thread computations = new Thread(new Runnable() {
-
-			@Override
-			public void run() {
-				if (async) {
-					// because we are running this in separate thread we need to open a
-					// new
-					// session for db connection
-					dbUtils.createSessionForCurrentThread();
-				}
-
-				Project project = projectDao.getById(p.getId());
-
-				try {
-					String email = null;
-					MapGenerator mapGenerator = new MapGenerator();
-					for (ModelData originalModel : project.getModels()) {
-						List<ModelData> models = new ArrayList<ModelData>();
-						models.add(originalModel);
-						for (ModelSubmodelConnection connection : originalModel.getSubmodels()) {
-							models.add(connection.getSubmodel());
-						}
-						modelService.removeModelFromCache(originalModel);
-						for (ModelData model : models) {
-							logger.debug("Remove model: " + model.getId());
-							commentService.removeCommentsForModel(model);
-
-							for (Layout layout : model.getLayouts()) {
-								try {
-									mapGenerator.removeLayout(layout, homeDir);
-								} catch (IOException e) {
-									logger.error("Problem with removing directory: " + layout.getDirectory(), e);
-								}
-							}
-						}
-						email = project.getNotifyEmail();
-					}
-					projectDao.delete(project);
-					if (async) {
-						projectDao.commit();
-					}
-
-					LogParams params = new LogParams().type(LogType.MAP_REMOVED).object(project);
-					logService.log(params);
-
-					if (email != null) {
-						try {
-							sendSuccesfullRemoveEmail(project.getProjectId(), email);
-						} catch (MessagingException e) {
-							logger.error("Problem with sending remove email.", e);
-						}
-					}
-					modelService.removeModelFromCacheByProjectId(p.getProjectId());
-
-				} catch (HibernateException e) {
-					logger.error("Problem with database", e);
-					handleHibernateExceptionRemovingReporting(project, e, token);
-				} finally {
-					if (async) {
-						// close the transaction for this thread
-						dbUtils.closeSessionForCurrentThread();
-					}
-				}
-				if (homeDir != null) {
-					File homeDirFile = new File(homeDir);
-					if (homeDirFile.exists()) {
-						logger.debug("Removing project directory: " + homeDirFile.getAbsolutePath());
-						try {
-							FileUtils.deleteDirectory(homeDirFile);
-						} catch (IOException e) {
-							logger.error("Problem with removing diriectory", e);
-						}
-					}
-				}
-
-			}
-		});
-
-		if (async) {
-			computations.start();
-		} else {
-			computations.run();
-		}
-
-	}
-
-	/**
-	 * When we encountered hibernate exception we need to handle error reporting
-	 * differently (hibernate session is broken). This method handles such case
-	 * when hibernate excedption occured when removing project.
-	 * 
-	 * @param originalProject
-	 *          project that was beining removed
-	 * @param exception
-	 *          hibernate exception that caused problems
-	 */
-	protected void handleHibernateExceptionRemovingReporting(Project originalProject, HibernateException exception, AuthenticationToken token) {
-		// we need to open separate thread because current one thrown db exception
-		// and transaction is corrupetd and will be rolledback
-		Thread reportInSeparateThread = new Thread(new Runnable() {
-
-			@Override
-			public void run() {
-				dbUtils.createSessionForCurrentThread();
-				try {
-					// we need to get the project from db, because session where
-					// originalProject was retrieved is broken
-					Project project = getProjectByProjectId(originalProject.getProjectId(), token);
-					String errorMessage = "Severe problem with removing object. Underlaying eror:\n" + exception.getMessage()
-							+ "\nMore information can be found in log file.";
-					project.setErrors(errorMessage + "\n" + project.getErrors());
-					project.setStatus(ProjectStatus.FAIL);
-					projectDao.update(project);
-				} catch (UserAccessException e) {
-					logger.error(e, e);
-				} finally {
-					dbUtils.closeSessionForCurrentThread();
-				}
-			}
-
-		});
-		reportInSeparateThread.start();
-	}
-
-	@Override
-	public void addProject(Project project) {
-		projectDao.add(project);
-
-	}
-
-	@Override
-	public ProjectView getProjectViewById(Integer id, AuthenticationToken token) throws UserAccessException {
-		Project project = projectDao.getById(id);
-		if (userService.userHasPrivilege(token, PrivilegeType.VIEW_PROJECT, project)) {
-			return projectViewFactory.create(project);
-		} else if (userService.userHasPrivilege(token, PrivilegeType.ADD_MAP)) {
-			return projectViewFactory.create(project);
-		} else {
-			throw new UserAccessException("User cannot access project");
-		}
-	}
-
-	/**
-	 * This methods add privileges for the users listed in params to the project.
-	 * 
-	 * @param project
-	 *          to which project we add privileges
-	 * @param params
-	 *          which users should be included to have privileges to the project
-	 */
-	private void addUsers(Project project, CreateProjectParams params) {
-		if (project == null) {
-			logger.warn("Users won't be added. Project not defined");
-			return;
-		}
-		List<String[]> users = params.getUsers();
-		String[][] newUsers = new String[users.size() + 1][2];
-		for (int i = 0; i < users.size(); i++) {
-			for (int j = 0; j < 2; j++) {
-				newUsers[i][j] = users.get(i)[j];
-			}
-		}
-		newUsers[users.size()][0] = "anonymous";
-		newUsers[users.size()][1] = "";
-		for (int i = 0; i < newUsers.length; i++) {
-			boolean admin = (users.size() != i);
-			String login = newUsers[i][0];
-			String passwd = newUsers[i][1];
-			User user = userService.getUserByLogin(login);
-			if (userService.getUserByLogin(login) == null) {
-				logger.debug("User " + login + " does not exist. Creating");
-				user = new User();
-				user.setCryptedPassword(passwordEncoder.encode(passwd));
-				user.setLogin(login);
-				userService.addUser(user);
-			}
-			if (project != null) {
-				logger.debug("Privileges for " + login + " for project " + project.getProjectId());
-				ObjectPrivilege privilege = new ObjectPrivilege(project, 1, PrivilegeType.VIEW_PROJECT, user);
-				userService.setUserPrivilege(user, privilege);
-				if (admin) {
-					privilege = new ObjectPrivilege(project, 1, PrivilegeType.LAYOUT_MANAGEMENT, user);
-					userService.setUserPrivilege(user, privilege);
-					privilege = new ObjectPrivilege(project, 1, PrivilegeType.EDIT_COMMENTS_PROJECT, user);
-					userService.setUserPrivilege(user, privilege);
-				}
-
-			}
-		}
-	}
-
-	/**
-	 * This method creates set of images for the model layouts.
-	 * 
-	 * @param originalModel
-	 *          model for which we create layout images
-	 * @param params
-	 *          configuration parameters including set of layouts to generate
-	 * @throws IOException
-	 *           thrown when there are problems with generating files
-	 * @throws DrawingException
-	 *           thrown when there was a problem with drawing a map
-	 * @throws CommandExecutionException
-	 *           thrown when one of the files describing layouts is invalid
-	 */
-	protected void createImages(final Model originalModel, final CreateProjectParams params) throws IOException, DrawingException, CommandExecutionException {
-		if (!params.isImages()) {
-			return;
-		}
-		updateProjectStatus(originalModel.getProject(), ProjectStatus.GENERATING_IMAGES, 0, params);
-
-		List<Model> models = new ArrayList<Model>();
-		models.add(originalModel);
-		int size = originalModel.getLayouts().size();
-		for (ModelSubmodelConnection connection : originalModel.getSubmodelConnections()) {
-			models.add(connection.getSubmodel().getModel());
-			size += connection.getSubmodel().getModel().getLayouts().size();
-		}
-		int counter = 0;
-		for (final Model model : models) {
-			for (int i = 0; i < model.getLayouts().size(); i++) {
-				Layout layout = model.getLayouts().get(i);
-				if (layout.getInputData() == null) {
-					final double imgCounter = counter;
-					final double finalSize = size;
-					IProgressUpdater updater = new IProgressUpdater() {
-						@Override
-						public void setProgress(double progress) {
-							updateProjectStatus(
-									originalModel.getProject(), ProjectStatus.GENERATING_IMAGES, IProgressUpdater.MAX_PROGRESS * imgCounter / finalSize + progress / finalSize,
-									params);
-						}
-					};
-
-					generateImagesForBuiltInOverlay(params, model, layout, updater);
-				}
-				counter++;
-			}
-		}
-	}
-
-	private void generateImagesForBuiltInOverlay(final CreateProjectParams params, final Model model, Layout layout, IProgressUpdater updater)
-			throws CommandExecutionException, IOException, DrawingException {
-		String directory = layout.getDirectory();
-		Model output = model;
-		if (layout.isHierarchicalView()) {
-			output = new CopyCommand(model).execute();
-			new SetFixedHierarchyLevelCommand(output, layout.getHierarchyViewLevel()).execute();
-		}
-		if (layout.getTitle().equals(BuildInLayout.CLEAN.getTitle())) {
-			output = new CopyCommand(model).execute();
-			new ClearColorModelCommand(output).execute();
-		}
-
-		MapGeneratorParams imgParams = generator.new MapGeneratorParams()
-				.directory(directory).sbgn(params.isSbgnFormat()).nested(layout.isHierarchicalView()).updater(updater);
-		imgParams.model(output);
-		generator.generateMapImages(imgParams);
-	}
-
-	/**
-	 * Creates project. Loads model from the input and run PostLoadModification.
-	 * 
-	 * @param params
-	 *          params used to create model
-	 * @param dbProject
-	 *          project where the model should be placed
-	 * @throws InvalidInputDataExecption
-	 *           thrown when there is a problem with input file
-	 */
-	protected void createModel(final CreateProjectParams params, Project dbProject) throws InvalidInputDataExecption {
-		ModelData modelData = modelDao.getLastModelForProjectIdentifier(params.getProjectId(), false);
-		if (modelData != null) {
-			throw new InvalidArgumentException("Model with the given name already exists");
-		}
-
-		final Project project = dbProject;
-		updateProjectStatus(project, ProjectStatus.PARSING_DATA, 0.0, params);
-
-		if (params.isComplex()) {
-			try {
-				Class<? extends IConverter> clazz = CellDesignerXmlParser.class;
-				if (params.getParser() != null) {
-					clazz = params.getParser().getClass();
-				}
-				ComplexZipConverter parser = new ComplexZipConverter(clazz);
-				ComplexZipConverterParams complexParams;
-				complexParams = new ComplexZipConverterParams().zipFile(params.getProjectFile());
-				complexParams.visualizationDir(params.getProjectDir());
-				for (ZipEntryFile entry : params.getZipEntries()) {
-					complexParams.entry(entry);
-				}
-				ProjectFactory projectFactory = new ProjectFactory(parser);
-				projectFactory.create(complexParams, dbProject);
-			} catch (IOException e) {
-				throw new InvalidInputDataExecption(e);
-			}
-		} else {
-			IConverter parser;
-			if (params.getParser() != null) {
-				parser = params.getParser();
-			} else if (params.getProjectFile().endsWith("sbgn")) {
-				parser = new SbgnmlXmlConverter();
-			} else {
-				parser = new CellDesignerXmlParser();
-			}
-			try {
-				Model model = parser
-						.createModel(new ConverterParams().filename(params.getProjectFile()).sizeAutoAdjust(params.isAutoResize()).sbgnFormat(params.isSbgnFormat()));
-				model.setName(params.getProjectName());
-				project.addModel(model);
-			} catch (FileNotFoundException ex) {
-				throw new InvalidInputDataExecption(ex);
-			}
-		}
-		Model topModel = project.getModels().iterator().next().getModel();
-		topModel.setZoomLevels(generator.computeZoomLevels(topModel));
-		topModel.setTileSize(MapGenerator.TILE_SIZE);
-		dbProject.setNotifyEmail(params.getNotifyEmail());
-
-		updateProjectStatus(project, ProjectStatus.UPLOADING_TO_DB, 0.0, params);
-		dbUtils.setAutoFlush(false);
-		projectDao.update(project);
-		dbUtils.setAutoFlush(true);
-		projectDao.flush();
-
-		List<BuildInLayout> buildInLayouts = new ArrayList<>();
-		BuildInLayout nested = null;
-		if (params.isSemanticZoom()) {
-			nested = BuildInLayout.SEMANTIC;
-		} else {
-			nested = BuildInLayout.NESTED;
-		}
-		if (params.isNetworkLayoutAsDefault()) {
-			buildInLayouts.add(BuildInLayout.NORMAL);
-			buildInLayouts.add(nested);
-		} else {
-			buildInLayouts.add(nested);
-			buildInLayouts.add(BuildInLayout.NORMAL);
-		}
-		buildInLayouts.add(BuildInLayout.CLEAN);
-
-		// reverse the order of build in layouts, so we can insert them at the
-		// beginning of list of layouts (the order will be the same)
-		Collections.reverse(buildInLayouts);
-
-		for (BuildInLayout buildInLayout : buildInLayouts) {
-			Layout topLayout = new Layout(
-					buildInLayout.getTitle(), params.getProjectDir() + "/" + buildInLayout.getDirectorySuffix() + topModel.getId() + "/", true);
-			topLayout.setStatus(LayoutStatus.NA);
-			topLayout.setProgress(0.0);
-			topLayout.setHierarchicalView(buildInLayout.isNested());
-			topModel.addLayout(0, topLayout);
-			int submodelId = 1;
-			List<Layout> semanticLevelOverlays = new ArrayList<>();
-			if (buildInLayout.equals(BuildInLayout.SEMANTIC)) {
-				for (int i = 0; i <= topModel.getZoomLevels(); i++) {
-					String directory = params.getProjectDir() + "/" + buildInLayout.getDirectorySuffix() + "-" + i + "-" + topModel.getId() + "/";
-					Layout semanticOverlay = new Layout(buildInLayout.getTitle() + "-" + i, directory, true);
-					semanticOverlay.setStatus(LayoutStatus.NA);
-					semanticOverlay.setProgress(0.0);
-					semanticOverlay.setHierarchicalView(buildInLayout.isNested());
-					semanticOverlay.setHierarchyViewLevel(i);
-					semanticLevelOverlays.add(semanticOverlay);
-					topModel.addLayout(1, semanticOverlay);
-				}
-			}
-			for (ModelSubmodelConnection connection : topModel.getSubmodelConnections()) {
-				Layout layout = new Layout(buildInLayout.getTitle(), params.getProjectDir() + "/" + buildInLayout.getDirectorySuffix() + submodelId + "/", true);
-				layout.setStatus(LayoutStatus.NA);
-				layout.setProgress(0.0);
-				layout.setHierarchicalView(buildInLayout.isNested());
-				layout.setParentLayout(topLayout);
-				connection.getSubmodel().addLayout(0, layout);
-
-				connection.getSubmodel().setZoomLevels(generator.computeZoomLevels(connection.getSubmodel().getModel()));
-				connection.getSubmodel().setTileSize(MapGenerator.TILE_SIZE);
-				if (buildInLayout.equals(BuildInLayout.SEMANTIC)) {
-					for (int i = 0; i <= topModel.getZoomLevels(); i++) {
-						String directory = params.getProjectDir() + "/" + buildInLayout.getDirectorySuffix() + "-" + i + "-" + submodelId + "/";
-						Layout semanticOverlay = new Layout(buildInLayout.getTitle() + "-" + i, directory, true);
-						semanticOverlay.setStatus(LayoutStatus.NA);
-						semanticOverlay.setProgress(0.0);
-						semanticOverlay.setHierarchicalView(buildInLayout.isNested());
-						semanticOverlay.setParentLayout(semanticLevelOverlays.get(i));
-						semanticOverlay.setHierarchyViewLevel(i);
-						connection.getSubmodel().addLayout(1, semanticOverlay);
-					}
-				}
-				submodelId++;
-			}
-		}
-
-		if (params.isUpdateAnnotations()) {
-			Map<Class<?>, List<ElementAnnotator>> annotators = null;
-			if (params.getAnnotatorsMap() != null) {
-				annotators = new HashMap<Class<?>, List<ElementAnnotator>>();
-				for (Class<?> clazz : params.getAnnotatorsMap().keySet()) {
-					annotators.put(clazz, modelAnnotator.getAnnotatorsFromCommonNames(params.getAnnotatorsMap().get(clazz)));
-				}
-			}
-			logger.debug("Updating annotations");
-			modelAnnotator.performAnnotations(topModel, new IProgressUpdater() {
-
-				@Override
-				public void setProgress(final double progress) {
-					updateProjectStatus(project, ProjectStatus.ANNOTATING, progress, params);
-				}
-			}, annotators);
-			logger.debug("Annotations updated");
-		}
-		updateProjectStatus(project, ProjectStatus.EXTENDING_MODEL, 0.0, params);
-		processDataMining(topModel, topModel.getDataMiningSets(), new IProgressUpdater() {
-
-			@Override
-			public void setProgress(double progress) {
-				updateProjectStatus(project, ProjectStatus.EXTENDING_MODEL, progress, params);
-			}
-
-		});
-		updateProjectStatus(project, ProjectStatus.EXTENDING_MODEL, IProgressUpdater.MAX_PROGRESS, params);
-		logger.debug("Model created");
-
-	}
-
-	/**
-	 * Process data mining files and assign suggested connections to the model.
-	 * 
-	 * @param model
-	 *          model where the suggested connections will be added
-	 * @param dataMiningSets
-	 *          set of files to process
-	 * @param progressUpdater
-	 *          callback function informing higher layer about progress
-	 * @throws InvalidDataMiningInputFile
-	 *           thrown when one of the files is invalid
-	 */
-	private void processDataMining(Model model, List<DataMiningSet> dataMiningSets, final IProgressUpdater progressUpdater) throws InvalidDataMiningInputFile {
-		Set<Element> nodes = new HashSet<>();
-		nodes.addAll(model.getElements());
-		for (ModelSubmodelConnection connection : model.getSubmodelConnections()) {
-			nodes.addAll(connection.getSubmodel().getElements());
-		}
-		Set<Reaction> reactions = new HashSet<Reaction>();
-		reactions.addAll(model.getReactions());
-		for (ModelSubmodelConnection connection : model.getSubmodelConnections()) {
-			reactions.addAll(connection.getSubmodel().getReactions());
-		}
-
-		int fileCounter = 0;
-		final int filesCount = dataMiningSets.size();
-		for (DataMiningSet dmSet : dataMiningSets) {
-
-			final double offset = IProgressUpdater.MAX_PROGRESS * fileCounter / filesCount;
-			IProgressUpdater secondPartUpdater = new IProgressUpdater() {
-
-				@Override
-				public void setProgress(double progress) {
-					progressUpdater.setProgress((progress * CREATION_OF_DATA) / ((double) filesCount) + offset);
-				}
-			};
-			Set<DataMining> result = dataMiningService.parseData(dmSet, nodes, reactions, secondPartUpdater);
-			double size = result.size();
-			double count = 0;
-
-			double updateOffset = IProgressUpdater.MAX_PROGRESS * fileCounter / filesCount + CREATION_OF_DATA / ((double) filesCount);
-			for (DataMining missingConnection : result) {
-				missingConnection.setType(dmSet.getType());
-				missingConnection.getElement().addDataMining(missingConnection);
-				count++;
-				progressUpdater.setProgress(updateOffset + IProgressUpdater.MAX_PROGRESS * count / size * UPLOAD_OF_DATA);
-			}
-		}
-	}
-
-	/**
-	 * Updates status of the generating project.
-	 * 
-	 * @param project
-	 *          project that is generated
-	 * @param status
-	 *          what is the current status
-	 * @param progress
-	 *          what is the progress
-	 * @param params
-	 *          parameters used for project creation
-	 */
-	private void updateProjectStatus(Project project, ProjectStatus status, double progress, CreateProjectParams params) {
-		if (project != null) {
-			if (!status.equals(project.getStatus()) || (Math.abs(progress - project.getProgress()) > IProgressUpdater.PROGRESS_BAR_UPDATE_RESOLUTION)) {
-				project.setStatus(status);
-				project.setProgress(progress);
-				projectDao.update(project);
-				if (params.isAsync()) {
-					projectDao.commit();
-				}
-			}
-		} else {
-			logger.debug("status: " + status + ", " + progress);
-		}
-	}
-
-	@Override
-	public void createProject(final CreateProjectParams params) throws SecurityException {
-		if (!userService.userHasPrivilege(params.getAuthenticationToken(), PrivilegeType.ADD_MAP)) {
-			throw new SecurityException("Adding projects not allowed.");
-		}
-
-		// this count down is used to wait for asynchronous thread to initialize
-		// data in the db (probably it would be better to move the initialization to
-		// main thread)
-		final CountDownLatch waitForInitialData = new CountDownLatch(1);
-
-		Thread computations = new Thread(new Runnable() {
-
-			@Override
-			public void run() {
-				if (params.isAsync()) {
-					// because we are running this in separate thread we need to open a
-					// new session for db connection
-					dbUtils.createSessionForCurrentThread();
-				}
-
-				Project project = new Project();
-				project.setProjectId(params.getProjectId());
-				project.setName(params.getProjectName());
-				if (params.getProjectDir() == null) {
-					logger.warn("Project directory not set");
-					project.setDirectory(null);
-				} else {
-					project.setDirectory(new File(params.getProjectDir()).getName());
-				}
-				project.setSbgnFormat(params.isSbgnFormat());
-
-				MiriamData disease = null;
-				if (params.getDisease() != null && !params.getDisease().isEmpty()) {
-					disease = new MiriamData(MiriamType.MESH_2012, params.getDisease());
-				}
-				MiriamData organism = null;
-				if (params.getOrganism() != null && !params.getOrganism().isEmpty()) {
-					organism = new MiriamData(MiriamType.TAXONOMY, params.getOrganism());
-				}
-				project.setVersion(params.getVersion());
-				projectDao.add(project);
-				if (params.isAsync()) {
-					projectDao.commit();
-				}
-				waitForInitialData.countDown();
-				double[] outOfMemoryBuffer;
-				EventStorageLoggerAppender appender = new EventStorageLoggerAppender();
-				try {
-					Logger.getRootLogger().addAppender(appender);
-					logger.debug("Running: " + params.getProjectId() + "; " + params.getProjectFile());
-					outOfMemoryBuffer = new double[OUT_OF_MEMORY_BACKUP_BUFFER_SIZE];
-					for (int i = 0; i < OUT_OF_MEMORY_BACKUP_BUFFER_SIZE; i++) {
-						outOfMemoryBuffer[i] = Math.random() * OUT_OF_MEMORY_BACKUP_BUFFER_SIZE;
-					}
-
-					File inputFile = new File(params.getProjectFile());
-					if (inputFile.exists()) {
-						UploadedFileEntry file = new UploadedFileEntry();
-						file.setFileContent(IOUtils.toByteArray(new FileInputStream(inputFile)));
-						file.setOriginalFileName(FilenameUtils.getName(params.getProjectFile()));
-						project.setInputData(file);
-					}
-
-					createModel(params, project);
-					Model originalModel = project.getModels().iterator().next().getModel();
-					if (!params.isSemanticZoom()) {
-						new CreateHierarchyCommand(originalModel, generator.computeZoomLevels(originalModel), generator.computeZoomFactor(originalModel)).execute();
-					}
-
-					addUsers(project, params);
-					createImages(originalModel, params);
-
-					for (Layout layout : originalModel.getLayouts()) {
-						String[] tmp = layout.getDirectory().split("[\\\\/]");
-						layout.setDirectory(tmp[tmp.length - 1]);
-					}
-					for (ModelSubmodelConnection connection : originalModel.getSubmodelConnections()) {
-						for (Layout layout : connection.getSubmodel().getLayouts()) {
-							String[] tmp = layout.getDirectory().split("[\\\\/]");
-							layout.setDirectory(tmp[tmp.length - 1]);
-						}
-					}
-
-					try {
-						if (meshParser.isValidMeshId(disease)) {
-							project.setDisease(disease);
-						} else {
-							logger.warn("No valid disease is provided for project:" + project.getName());
-						}
-					} catch (AnnotatorException e1) {
-						logger.warn("Problem with accessing mesh db. More info in logs.");
-					}
-
-					if (taxonomyBackend.getNameForTaxonomy(organism) != null) {
-						project.setOrganism(organism);
-					} else {
-						logger.warn("No valid organism is provided for project:" + project.getName());
-					}
-
-					modelDao.update(originalModel);
-
-					if (params.isCacheModel()) {
-						cacheData(originalModel, params);
-					}
-
-					if (params.isAnalyzeAnnotations()) {
-						analyzeAnnotations(originalModel, params);
-					}
-					Logger.getRootLogger().removeAppender(appender);
-					project.addLoggingInfo(appender);
-					updateProjectStatus(project, ProjectStatus.DONE, IProgressUpdater.MAX_PROGRESS, params);
-					if (project.getNotifyEmail() != null && !project.getNotifyEmail().equals("")) {
-						try {
-							sendSuccesfullEmail(originalModel);
-						} catch (MessagingException e) {
-							logger.error(e, e);
-						}
-					}
-
-					LogParams params = new LogParams().description("Created successfully").type(LogType.MAP_CREATED).object(originalModel);
-					logService.log(params);
-
-				} catch (HibernateException e) {
-					outOfMemoryBuffer = null;
-					logger.error("Problem with database", e);
-					handleHibernateExceptionReporting(params, e);
-				} catch (Exception e) {
-					outOfMemoryBuffer = null;
-					handleCreateProjectException(params, e);
-				} catch (OutOfMemoryError oome) {
-					// release some memory
-					outOfMemoryBuffer = null;
-					logger.error("Out of memory", oome);
-					if (project != null) {
-						project.setErrors("Out of memory: " + oome.getMessage());
-					}
-					updateProjectStatus(project, ProjectStatus.FAIL, IProgressUpdater.MAX_PROGRESS, params);
-				} finally {
-					if (params.isAsync()) {
-						// close the transaction for this thread
-						dbUtils.closeSessionForCurrentThread();
-					}
-					Logger.getRootLogger().removeAppender(appender);
-				}
-			}
-		});
-		if (params.isAsync()) {
-			computations.start();
-		} else {
-			computations.run();
-		}
-
-		try {
-			waitForInitialData.await();
-		} catch (InterruptedException e1) {
-			logger.error(e1, e1);
-		}
-
-	}
-
-	/**
-	 * Cache pubmed data for the model.
-	 * 
-	 * @param originalModel
-	 *          model for which we want to cache data.
-	 * @param params
-	 *          parameters used for model generation
-	 */
-	private void cacheData(final Model originalModel, final CreateProjectParams params) {
-		modelService.cacheAllPubmedIds(originalModel, new IProgressUpdater() {
-			@Override
-			public void setProgress(double progress) {
-				updateProjectStatus(originalModel.getProject(), ProjectStatus.CACHING, progress, params);
-			}
-		});
-		modelService.cacheAllMiriamLinks(originalModel, new IProgressUpdater() {
-			@Override
-			public void setProgress(double progress) {
-				updateProjectStatus(originalModel.getProject(), ProjectStatus.CACHING_MIRIAM, progress, params);
-			}
-		});
-
-		chemicalService.cacheDataForModel(originalModel, new IProgressUpdater() {
-			@Override
-			public void setProgress(double progress) {
-				updateProjectStatus(originalModel.getProject(), ProjectStatus.CACHING_CHEMICAL, progress, params);
-			}
-		});
-
-		drugService.cacheDataForModel(originalModel, new IProgressUpdater() {
-			@Override
-			public void setProgress(double progress) {
-				updateProjectStatus(originalModel.getProject(), ProjectStatus.CACHING_DRUG, progress, params);
-			}
-		});
-
-		mirnaService.cacheDataForModel(originalModel, new IProgressUpdater() {
-			@Override
-			public void setProgress(double progress) {
-				updateProjectStatus(originalModel.getProject(), ProjectStatus.CACHING_MI_RNA, progress, params);
-			}
-		});
-
-	}
-
-	/**
-	 * @return the modelDao
-	 * @see #modelDao
-	 */
-	public ModelDao getModelDao() {
-		return modelDao;
-	}
-
-	/**
-	 * @param modelDao
-	 *          the modelDao to set
-	 * @see #modelDao
-	 */
-	public void setModelDao(ModelDao modelDao) {
-		this.modelDao = modelDao;
-	}
-
-	/**
-	 * @return the commentService
-	 * @see #commentService
-	 */
-	public ICommentService getCommentService() {
-		return commentService;
-	}
-
-	/**
-	 * @param commentService
-	 *          the commentService to set
-	 * @see #commentService
-	 */
-	public void setCommentService(ICommentService commentService) {
-		this.commentService = commentService;
-	}
-
-	/**
-	 * @return the passwordEncoder
-	 * @see #passwordEncoder
-	 */
-	public PasswordEncoder getPasswordEncoder() {
-		return passwordEncoder;
-	}
-
-	/**
-	 * @param passwordEncoder
-	 *          the passwordEncoder to set
-	 * @see #passwordEncoder
-	 */
-	public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
-		this.passwordEncoder = passwordEncoder;
-	}
-
-	/**
-	 * @return the commentDao
-	 * @see #commentDao
-	 */
-	public CommentDao getCommentDao() {
-		return commentDao;
-	}
-
-	/**
-	 * @param commentDao
-	 *          the commentDao to set
-	 * @see #commentDao
-	 */
-	public void setCommentDao(CommentDao commentDao) {
-		this.commentDao = commentDao;
-	}
-
-	/**
-	 * @return the modelAnnotator
-	 * @see #modelAnnotator
-	 */
-	public ModelAnnotator getModelAnnotator() {
-		return modelAnnotator;
-	}
-
-	/**
-	 * @param modelAnnotator
-	 *          the modelAnnotator to set
-	 * @see #modelAnnotator
-	 */
-	public void setModelAnnotator(ModelAnnotator modelAnnotator) {
-		this.modelAnnotator = modelAnnotator;
-	}
-
-	/**
-	 * @return the dbUtils
-	 * @see #dbUtils
-	 */
-	public DbUtils getDbUtils() {
-		return dbUtils;
-	}
-
-	/**
-	 * @param dbUtils
-	 *          the dbUtils to set
-	 * @see #dbUtils
-	 */
-	public void setDbUtils(DbUtils dbUtils) {
-		this.dbUtils = dbUtils;
-	}
-
-	/**
-	 * @return the projectDao
-	 * @see #projectDao
-	 */
-	public ProjectDao getProjectDao() {
-		return projectDao;
-	}
-
-	/**
-	 * @param projectDao
-	 *          the projectDao to set
-	 * @see #projectDao
-	 */
-	public void setProjectDao(ProjectDao projectDao) {
-		this.projectDao = projectDao;
-	}
-
-	/**
-	 * @return the dataMiningService
-	 * @see #dataMiningService
-	 */
-	public IDataMiningService getDataMiningService() {
-		return dataMiningService;
-	}
-
-	/**
-	 * @param dataMiningService
-	 *          the dataMiningService to set
-	 * @see #dataMiningService
-	 */
-	public void setDataMiningService(IDataMiningService dataMiningService) {
-		this.dataMiningService = dataMiningService;
-	}
-
-	@Override
-	public ProjectView createEmpty() {
-		return projectViewFactory.create(null);
-	}
-
-	/**
-	 * Analyzes annotation of the model and put information about invalid
-	 * annotations into the {@link Model#creationWarnings} field.
-	 * 
-	 * @param originalModel
-	 *          model to analyze
-	 * @param params
-	 *          parameters used for model generation
-	 */
-	protected void analyzeAnnotations(final Model originalModel, final CreateProjectParams params) {
-		logger.debug("Analyze annotations");
-		Collection<? extends ProblematicAnnotation> improperAnnotations = modelAnnotator.findImproperAnnotations(originalModel, new IProgressUpdater() {
-
-			@Override
-			public void setProgress(double progress) {
-				updateProjectStatus(originalModel.getProject(), ProjectStatus.VALIDATING_MIRIAM, progress, params);
-			}
-		}, params.getValidAnnotations());
-		List<String> res = new ArrayList<>();
-		for (ProblematicAnnotation improperAnnotation : improperAnnotations) {
-			res.add(improperAnnotation.toString());
-		}
-		Collections.sort(res);
-
-		Collection<? extends ProblematicAnnotation> missingAnnotations = modelAnnotator.findMissingAnnotations(originalModel, params.getRequiredAnnotations());
-		for (ProblematicAnnotation improperAnnotation : missingAnnotations) {
-			res.add(improperAnnotation.toString());
-		}
-		for (String message : res) {
-			logger.warn(message);
-		}
-		logger.debug("Analyze finished");
-	}
-
-	/**
-	 * Sends notification email that map was removed.
-	 * 
-	 * @param projectId
-	 *          identifier of the project
-	 * @param email
-	 *          otification email
-	 * @throws MessagingException
-	 *           thrown when there is a problem with sending email
-	 */
-	protected void sendSuccesfullRemoveEmail(String projectId, String email) throws MessagingException {
-		EmailSender emailSender = new EmailSender(configurationService);
-		StringBuilder content = new StringBuilder("Map " + projectId + " was successfully removed.<br/>");
-		emailSender.sendEmail("MapViewer notification", content.toString(), email);
-	}
-
-	@Override
-	public TreeNode createClassAnnotatorTree(User user) {
-
-		UserAnnotationSchema annotationSchema = prepareUserAnnotationSchema(user);
-
-		ElementUtils elementUtils = new ElementUtils();
-
-		ClassTreeNode top = elementUtils.getAnnotatedElementClassTree();
-
-		Class<?> clazz = top.getClazz();
-		TreeNode root = new DefaultTreeNode(
-				new AnnotatedObjectTreeRow(
-						top, modelAnnotator.getAvailableAnnotators(clazz), modelAnnotator.getAnnotatorsFromCommonNames(annotationSchema.getAnnotatorsForClass(clazz)),
-						annotationSchema.getValidAnnotations(clazz), annotationSchema.getRequiredAnnotations(clazz)),
-				null);
-
-		root.setExpanded(true);
-
-		Queue<Pair<ClassTreeNode, TreeNode>> nodes = new LinkedList<Pair<ClassTreeNode, TreeNode>>();
-		nodes.add(new Pair<ClassTreeNode, TreeNode>(top, root));
-		// create children
-
-		Queue<TreeNode> expandParents = new LinkedList<TreeNode>();
-
-		while (!nodes.isEmpty()) {
-			Pair<ClassTreeNode, TreeNode> element = nodes.poll();
-
-			for (ClassTreeNode node : element.getLeft().getChildren()) {
-
-				clazz = node.getClazz();
-				AnnotatedObjectTreeRow data = new AnnotatedObjectTreeRow(
-						node, modelAnnotator.getAvailableAnnotators(clazz), modelAnnotator.getAnnotatorsFromCommonNames(annotationSchema.getAnnotatorsForClass(clazz)),
-						annotationSchema.getValidAnnotations(clazz), annotationSchema.getRequiredAnnotations(clazz));
-				TreeNode treeNode = new DefaultTreeNode(data, element.getRight());
-				nodes.add(new Pair<ClassTreeNode, TreeNode>(node, treeNode));
-				if (data.getUsedAnnotators().size() > 0 || data.getValidAnnotators().size() > 0) {
-					expandParents.add(treeNode);
-				}
-			}
-		}
-		while (!expandParents.isEmpty()) {
-			TreeNode node = expandParents.poll();
-			if (node.getParent() != null && !node.getParent().isExpanded()) {
-				node.getParent().setExpanded(true);
-				expandParents.add(node.getParent());
-			}
-		}
-
-		return root;
-
-	}
-
-	/**
-	 * Retrieves (or creates) annotation schema for a given user.
-	 * 
-	 * @param user
-	 *          for this users {@link UserAnnotationSchema} will be prepared
-	 * @return {@link UserAnnotationSchema} for {@link User}
-	 */
-	public UserAnnotationSchema prepareUserAnnotationSchema(User user) {
-		UserAnnotationSchema annotationSchema = null;
-		if (user != null) {
-			annotationSchema = userDao.getById(user.getId()).getAnnotationSchema();
-		}
-		if (annotationSchema == null) {
-			annotationSchema = new UserAnnotationSchema();
-
-			ElementUtils elementUtils = new ElementUtils();
-
-			ClassTreeNode top = elementUtils.getAnnotatedElementClassTree();
-
-			Map<Class<? extends BioEntity>, Set<MiriamType>> validMiriam = modelAnnotator.getDefaultValidClasses();
-			Map<Class<? extends BioEntity>, Set<MiriamType>> requiredMiriam = modelAnnotator.getDefaultRequiredClasses();
-
-			Queue<ClassTreeNode> nodes = new LinkedList<ClassTreeNode>();
-			nodes.add(top);
-
-			while (!nodes.isEmpty()) {
-				ClassTreeNode element = nodes.poll();
-				annotationSchema.addClassAnnotator(new UserClassAnnotators(element.getClazz(), modelAnnotator.getAvailableDefaultAnnotatorNames(element.getClazz())));
-				annotationSchema.addClassValidAnnotations(new UserClassValidAnnotations(element.getClazz(), validMiriam.get(element.getClazz())));
-				annotationSchema.addClassRequiredAnnotations(new UserClassRequiredAnnotations(element.getClazz(), requiredMiriam.get(element.getClazz())));
-				for (ClassTreeNode node : element.getChildren()) {
-					nodes.add(node);
-				}
-			}
-			User dbUser = userDao.getById(user.getId());
-			dbUser.setAnnotationSchema(annotationSchema);
-			userDao.update(dbUser);
-		}
-		return annotationSchema;
-	}
-
-	@Override
-	public void updateClassAnnotatorTreeForUser(User user, TreeNode annotatorsTree, boolean sbgnFormat, boolean networkLayoutAsDefault) {
-		User dbUser = userDao.getById(user.getId());
-		if (dbUser.getAnnotationSchema() == null) {
-			dbUser.setAnnotationSchema(new UserAnnotationSchema());
-		}
-		UserAnnotationSchema annotationSchema = dbUser.getAnnotationSchema();
-
-		Queue<TreeNode> queue = new LinkedList<TreeNode>();
-		queue.add(annotatorsTree);
-		while (!queue.isEmpty()) {
-			TreeNode node = queue.poll();
-			for (TreeNode child : node.getChildren()) {
-				queue.add(child);
-			}
-			AnnotatedObjectTreeRow data = (AnnotatedObjectTreeRow) node.getData();
-			annotationSchema.addClassAnnotator(new UserClassAnnotators(data.getClazz(), data.getUsedAnnotators()));
-			annotationSchema.addClassRequiredAnnotations(new UserClassRequiredAnnotations(data.getClazz(), data.getRequiredAnnotations()));
-			annotationSchema.addClassValidAnnotations(new UserClassValidAnnotations(data.getClazz(), data.getValidAnnotations()));
-		}
-		annotationSchema.setSbgnFormat(sbgnFormat);
-		annotationSchema.setNetworkLayoutAsDefault(networkLayoutAsDefault);
-		userService.updateUser(dbUser);
-		user.setAnnotationSchema(annotationSchema);
-	}
-
-	/**
-	 * Sends email about unsuccessfull project creation.
-	 * 
-	 * @param projectName
-	 *          name of the project
-	 * @param email
-	 *          email where we want to send information
-	 * @param e
-	 *          exception that caused problem
-	 */
-	private void sendUnsuccesfullEmail(String projectName, String email, Exception e) {
-		EmailSender emailSender = new EmailSender(configurationService);
-		StringBuilder content = new StringBuilder("");
-		content.append("There was a problem with generating " + projectName + " map.<br/>");
-		content.append(e.getClass().getName() + ": " + e.getMessage());
-		try {
-			emailSender.sendEmail("MapViewer notification", content.toString(), email);
-		} catch (MessagingException e1) {
-			logger.error(e1);
-		}
-	}
-
-	/**
-	 * Sends email about successfull project creation.
-	 * 
-	 * @param originalModel
-	 *          model that was created
-	 * @throws MessagingException
-	 *           exception thrown when there is a problem with sending email
-	 */
-	protected void sendSuccesfullEmail(Model originalModel) throws MessagingException {
-		EmailSender emailSender = new EmailSender(configurationService);
-		StringBuilder content = new StringBuilder("Your map was generated successfully.<br/>");
-		emailSender.sendEmail("MapViewer notification", content.toString(), originalModel.getProject().getNotifyEmail());
-	}
-
-	@Override
-	public void updateProject(Project project) {
-		projectDao.update(project);
-	}
-
-	/**
-	 * This method handles situation when sever db error appeard during uploading
-	 * of the project into database.
-	 * 
-	 * @param params
-	 *          parameters used to create project
-	 * @param e
-	 *          exception that occured during uploading of the project
-	 */
-	private void handleHibernateExceptionReporting(CreateProjectParams params, HibernateException e) {
-		// we need to open separate thread because current one thrown db exception
-		// and transaction is corrupetd and will be rolledback
-		Thread reportInSeparateThread = new Thread(new Runnable() {
-
-			@Override
-			public void run() {
-				dbUtils.createSessionForCurrentThread();
-
-				try {
-					Project project = getProjectByProjectId(params.getProjectId(), params.getAuthenticationToken());
-					String errorMessage = "Problem with uploading to database. "
-							+ "You might violated some unhandled constraints or you run out of memory. Underlaying eror:\n" + e.getMessage()
-							+ "\nMore information can be found in log file.";
-					project.setErrors(errorMessage);
-					project.setStatus(ProjectStatus.FAIL);
-					projectDao.update(project);
-				} catch (Exception e) {
-					logger.error(e, e);
-				} finally {
-					dbUtils.closeSessionForCurrentThread();
-				}
-			}
-
-		});
-		reportInSeparateThread.start();
-
-	}
-
-	@Override
-	public byte[] getInputDataForProject(ProjectView projectView) {
-		return getInputDataForProject(projectView.getIdObject());
-	}
-
-	/**
-	 * Returns byte array containing data from original input file that was used
-	 * to create this project.
-	 * 
-	 * @param projectId
-	 *          identifier of project for which we want to retrieve original file
-	 *          data
-	 * @return original data file for given layout, if such file is not stored in
-	 *         database (compatibility reasons) then null is returned
-	 */
-	private byte[] getInputDataForProject(int projectId) {
-		Project project = projectDao.getById(projectId);
-		if (project == null || project.getInputData() == null) {
-			return null;
-		} else {
-			return project.getInputData().getFileContent();
-		}
-	}
-
-	/**
-	 * Method that handles exception reporting during creation of a project.
-	 * 
-	 * @param params
-	 *          set of parameters used to create project
-	 * @param e
-	 *          exception that caused problems
-	 */
-	private void handleCreateProjectException(final CreateProjectParams params, Exception e) {
-		Project p = projectDao.getProjectByProjectId(params.getProjectId());
-		logger.error(e.getMessage(), e);
-		if (p != null) {
-			p.setErrors("Problem with uploading map: " + e.getMessage() + ". More details can be found in log file.");
-		}
-		updateProjectStatus(p, ProjectStatus.FAIL, IProgressUpdater.MAX_PROGRESS, params);
-
-		String email = params.getNotifyEmail();
-		String projectName = params.getProjectId();
-
-		LogParams logParams = new LogParams().description("Failed: " + e.getMessage()).type(LogType.MAP_CREATED).object(p);
-		logService.log(logParams);
-		if (email != null) {
-			sendUnsuccesfullEmail(projectName, email, e);
-		}
-	}
-
-	/**
-	 * @return the taxonomyBackend
-	 * @see #taxonomyBackend
-	 */
-	public TaxonomyBackend getTaxonomyBackend() {
-		return taxonomyBackend;
-	}
-
-	/**
-	 * @param taxonomyBackend
-	 *          the taxonomyBackend to set
-	 * @see #taxonomyBackend
-	 */
-	public void setTaxonomyBackend(TaxonomyBackend taxonomyBackend) {
-		this.taxonomyBackend = taxonomyBackend;
-	}
+  /**
+   * Size of the artifitial buffer that will be released when
+   * {@link OutOfMemoryError} is thrown to gain some free memory and report
+   * problem.
+   */
+  private static final int OUT_OF_MEMORY_BACKUP_BUFFER_SIZE = 10000;
+
+  /**
+   * How much time (out of 1.00) is used for creation of the data from file.
+   */
+  private static final double CREATION_OF_DATA = 0.50;
+
+  /**
+   * How much time (out of 1.00) is used for upploading of the data from file.
+   */
+  private static final double UPLOAD_OF_DATA = 0.50;
+
+  /**
+   * Default class logger.
+   */
+  private Logger logger = Logger.getLogger(ProjectService.class);
+
+  /**
+   * Data access object for projects.
+   */
+  @Autowired
+  private ProjectDao projectDao;
+
+  /**
+   * Data access object for models.
+   */
+  @Autowired
+  private ModelDao modelDao;
+
+  /**
+   * Data access object for users.
+   */
+  @Autowired
+  private UserDao userDao;
+
+  /**
+   * Service that allows to access and manage models.
+   */
+  @Autowired
+  private IModelService modelService;
+
+  /**
+   * Service that allows to access and manage comments.
+   */
+  @Autowired
+  private ICommentService commentService;
+
+  /**
+   * Service used to access logs.
+   * 
+   * @see ILogService
+   */
+  @Autowired
+  private ILogService logService;
+
+  /**
+   * Service that manages and gives access to configuration parameters.
+   */
+  @Autowired
+  private IConfigurationService configurationService;
+
+  /**
+   * Services that manages and gives access to user information.
+   */
+  @Autowired
+  private IUserService userService;
+
+  /**
+   * Services that accessa data about chemicals.
+   */
+  @Autowired
+  private IChemicalService chemicalService;
+
+  /**
+   * Services that accessa data about drugs.
+   */
+  @Autowired
+  private IDrugService drugService;
+
+  /**
+   * Services that accessa data about mirna.
+   */
+  @Autowired
+  private IMiRNAService mirnaService;
+
+  /**
+   * Service that manages data mining information.
+   */
+  @Autowired
+  private IDataMiningService dataMiningService;
+
+  /**
+   * Data access object for comments.
+   */
+  @Autowired
+  private CommentDao commentDao;
+
+  /**
+   * Service that provides password encoding.
+   */
+  @Autowired
+  private PasswordEncoder passwordEncoder;
+
+  /**
+   * Module that allows to annotate maps.
+   */
+  @Autowired
+  private ModelAnnotator modelAnnotator;
+
+  /**
+   * Utils that help to manage the sessions in custom multithreaded
+   * implementation.
+   */
+  @Autowired
+  private DbUtils dbUtils;
+
+  /**
+   * Factory object for {@link ProjectView} elements.
+   */
+  @Autowired
+  private ProjectViewFactory projectViewFactory;
+
+  /**
+   * Access point and parser for the online ctd database.
+   */
+  @Autowired
+  private MeSHParser meshParser;
+
+  /**
+   * Access point and parser for the online ctd database.
+   */
+  @Autowired
+  private TaxonomyBackend taxonomyBackend;
+
+  /**
+   * Class that helps to generate images for google maps API.
+   */
+  private MapGenerator generator = new MapGenerator();
+
+  @Override
+  public Project getProjectByProjectId(String name, AuthenticationToken token) throws UserAccessException {
+    Project result = projectDao.getProjectByProjectId(name);
+    if (result == null) {
+      return result;
+    }
+    if (userService.userHasPrivilege(token, PrivilegeType.VIEW_PROJECT, result)) {
+      return result;
+    } else if (userService.userHasPrivilege(token, PrivilegeType.ADD_MAP)) {
+      return result;
+    }
+    throw new UserAccessException("User cannot access project");
+  }
+
+  @Override
+  public boolean projectExists(String projectName) {
+    if (projectName == null || projectName.equals("")) {
+      return false;
+    }
+    return projectDao.isProjectExistsByName(projectName);
+  }
+
+  @Override
+  public List<Project> getAllProjects(AuthenticationToken token) {
+    List<Project> projects = projectDao.getAll();
+    if (userService.userHasPrivilege(token, PrivilegeType.ADD_MAP)) {
+      return projects;
+    }
+    List<Project> result = new ArrayList<>();
+    for (Project project : projects) {
+      if (userService.userHasPrivilege(token, PrivilegeType.VIEW_PROJECT, project)) {
+        result.add(project);
+      }
+    }
+    return result;
+  }
+
+  @Override
+  public List<ProjectView> getAllProjectViews(AuthenticationToken token) {
+    List<ProjectView> result = new ArrayList<>();
+    List<Project> projects = getAllProjects(token);
+    for (Project project : projects) {
+      result.add(projectViewFactory.create(project));
+    }
+    return result;
+  }
+
+  @Override
+  public void updateProject(ProjectView selectedProject) {
+    Project project = projectDao.getById(selectedProject.getIdObject());
+    project.setProjectId(selectedProject.getProjectId());
+    project.setName(selectedProject.getProjectName());
+    project.setVersion(selectedProject.getVersion());
+    project.setNotifyEmail(selectedProject.getNotifyEmail());
+    MiriamData disease = null;
+    MiriamData organism = null;
+    if (selectedProject.getNewDiseaseName() != null && !selectedProject.getNewDiseaseName().isEmpty()) {
+      disease = new MiriamData(MiriamType.MESH_2012, selectedProject.getNewDiseaseName());
+    }
+    if (selectedProject.getNewOrganismName() != null && !selectedProject.getNewOrganismName().isEmpty()) {
+      organism = new MiriamData(MiriamType.TAXONOMY, selectedProject.getNewOrganismName());
+    }
+    try {
+      if (meshParser.isValidMeshId(disease)) {
+        project.setDisease(disease);
+      } else {
+        project.setDisease(null);
+        selectedProject.setNewDiseaseName(null);
+      }
+    } catch (AnnotatorException e) {
+      logger.error("Problem with accessing mesh", e);
+      project.setDisease(null);
+      selectedProject.setNewDiseaseName(null);
+    }
+    try {
+      if (taxonomyBackend.getNameForTaxonomy(organism) != null) {
+        project.setOrganism(organism);
+      } else {
+        project.setOrganism(null);
+        selectedProject.setNewOrganismName(null);
+      }
+    } catch (TaxonomySearchException e) {
+      logger.error("Problem with accessing taxonomy db", e);
+      project.setOrganism(null);
+      selectedProject.setNewOrganismName(null);
+    }
+    for (ModelData model : project.getModels()) {
+      if (model.getId().equals(selectedProject.getModelId())) {
+        modelService.updateModel(model, selectedProject);
+      }
+    }
+    projectDao.update(project);
+  }
+
+  @Override
+  public void removeProject(ProjectView selectedProject, String homeDir, boolean async, AuthenticationToken token)
+      throws UserAccessException {
+    Project project = projectDao.getById(selectedProject.getIdObject());
+    removeProject(project, homeDir, async, token);
+  }
+
+  /**
+   * Removes all types of privileges from every user to the project given in the
+   * parameter.
+   * 
+   * @param project
+   *          from which project we remove privileges
+   */
+  private void removePrivilegesForProject(Project project) {
+    for (PrivilegeType type : PrivilegeType.values()) {
+      if (type.getPrivilegeObjectType() == Project.class) {
+        userService.dropPrivilegesForObjectType(type, project.getId());
+      }
+    }
+  }
+
+  @Override
+  public ProjectView getProjectViewByProjectId(String name, AuthenticationToken token) throws UserAccessException {
+    Project project = getProjectByProjectId(name, token);
+    return projectViewFactory.create(project);
+  }
+
+  @Override
+  public void removeProject(final Project p, final String dir, final boolean async, AuthenticationToken token)
+      throws UserAccessException {
+    if (!userService.userHasPrivilege(userService.getUserByToken(token), PrivilegeType.PROJECT_MANAGEMENT)) {
+      throw new UserAccessException("User cannot remove project");
+    }
+
+    final String homeDir;
+    if (dir != null) {
+      if (p.getDirectory() != null) {
+        homeDir = dir + "/../map_images/" + p.getDirectory() + "/";
+      } else {
+        homeDir = dir + "/../map_images/";
+      }
+    } else {
+      if (p.getDirectory() != null) {
+        homeDir = p.getDirectory() + "/";
+      } else {
+        homeDir = null;
+      }
+    }
+    removePrivilegesForProject(p);
+    updateProjectStatus(p, ProjectStatus.REMOVING, 0, new CreateProjectParams());
+    Thread computations = new Thread(new Runnable() {
+
+      @Override
+      public void run() {
+        if (async) {
+          // because we are running this in separate thread we need to open a
+          // new
+          // session for db connection
+          dbUtils.createSessionForCurrentThread();
+        }
+
+        Project project = projectDao.getById(p.getId());
+
+        try {
+          String email = null;
+          MapGenerator mapGenerator = new MapGenerator();
+          for (ModelData originalModel : project.getModels()) {
+            List<ModelData> models = new ArrayList<ModelData>();
+            models.add(originalModel);
+            for (ModelSubmodelConnection connection : originalModel.getSubmodels()) {
+              models.add(connection.getSubmodel());
+            }
+            modelService.removeModelFromCache(originalModel);
+            for (ModelData model : models) {
+              logger.debug("Remove model: " + model.getId());
+              commentService.removeCommentsForModel(model);
+
+              for (Layout layout : model.getLayouts()) {
+                try {
+                  mapGenerator.removeLayout(layout, homeDir);
+                } catch (IOException e) {
+                  logger.error("Problem with removing directory: " + layout.getDirectory(), e);
+                }
+              }
+            }
+            email = project.getNotifyEmail();
+          }
+          projectDao.delete(project);
+          if (async) {
+            projectDao.commit();
+          }
+
+          LogParams params = new LogParams().type(LogType.MAP_REMOVED).object(project);
+          logService.log(params);
+
+          if (email != null) {
+            try {
+              sendSuccesfullRemoveEmail(project.getProjectId(), email);
+            } catch (MessagingException e) {
+              logger.error("Problem with sending remove email.", e);
+            }
+          }
+          modelService.removeModelFromCacheByProjectId(p.getProjectId());
+
+        } catch (HibernateException e) {
+          logger.error("Problem with database", e);
+          handleHibernateExceptionRemovingReporting(project, e, token);
+        } finally {
+          if (async) {
+            // close the transaction for this thread
+            dbUtils.closeSessionForCurrentThread();
+          }
+        }
+        if (homeDir != null) {
+          File homeDirFile = new File(homeDir);
+          if (homeDirFile.exists()) {
+            logger.debug("Removing project directory: " + homeDirFile.getAbsolutePath());
+            try {
+              FileUtils.deleteDirectory(homeDirFile);
+            } catch (IOException e) {
+              logger.error("Problem with removing diriectory", e);
+            }
+          }
+        }
+
+      }
+    });
+
+    if (async) {
+      computations.start();
+    } else {
+      computations.run();
+    }
+
+  }
+
+  /**
+   * When we encountered hibernate exception we need to handle error reporting
+   * differently (hibernate session is broken). This method handles such case when
+   * hibernate excedption occured when removing project.
+   * 
+   * @param originalProject
+   *          project that was beining removed
+   * @param exception
+   *          hibernate exception that caused problems
+   */
+  protected void handleHibernateExceptionRemovingReporting(Project originalProject, HibernateException exception,
+      AuthenticationToken token) {
+    // we need to open separate thread because current one thrown db exception
+    // and transaction is corrupetd and will be rolledback
+    Thread reportInSeparateThread = new Thread(new Runnable() {
+
+      @Override
+      public void run() {
+        dbUtils.createSessionForCurrentThread();
+        try {
+          // we need to get the project from db, because session where
+          // originalProject was retrieved is broken
+          Project project = getProjectByProjectId(originalProject.getProjectId(), token);
+          String errorMessage = "Severe problem with removing object. Underlaying eror:\n" + exception.getMessage()
+              + "\nMore information can be found in log file.";
+          project.setErrors(errorMessage + "\n" + project.getErrors());
+          project.setStatus(ProjectStatus.FAIL);
+          projectDao.update(project);
+        } catch (UserAccessException e) {
+          logger.error(e, e);
+        } finally {
+          dbUtils.closeSessionForCurrentThread();
+        }
+      }
+
+    });
+    reportInSeparateThread.start();
+  }
+
+  @Override
+  public void addProject(Project project) {
+    projectDao.add(project);
+
+  }
+
+  @Override
+  public ProjectView getProjectViewById(Integer id, AuthenticationToken token) throws UserAccessException {
+    Project project = projectDao.getById(id);
+    if (userService.userHasPrivilege(token, PrivilegeType.VIEW_PROJECT, project)) {
+      return projectViewFactory.create(project);
+    } else if (userService.userHasPrivilege(token, PrivilegeType.ADD_MAP)) {
+      return projectViewFactory.create(project);
+    } else {
+      throw new UserAccessException("User cannot access project");
+    }
+  }
+
+  /**
+   * This methods add privileges for the users listed in params to the project.
+   * 
+   * @param project
+   *          to which project we add privileges
+   * @param params
+   *          which users should be included to have privileges to the project
+   */
+  private void addUsers(Project project, CreateProjectParams params) {
+    if (project == null) {
+      logger.warn("Users won't be added. Project not defined");
+      return;
+    }
+    List<String[]> users = params.getUsers();
+    String[][] newUsers = new String[users.size() + 1][2];
+    for (int i = 0; i < users.size(); i++) {
+      for (int j = 0; j < 2; j++) {
+        newUsers[i][j] = users.get(i)[j];
+      }
+    }
+    newUsers[users.size()][0] = "anonymous";
+    newUsers[users.size()][1] = "";
+    for (int i = 0; i < newUsers.length; i++) {
+      boolean admin = (users.size() != i);
+      String login = newUsers[i][0];
+      String passwd = newUsers[i][1];
+      User user = userService.getUserByLogin(login);
+      if (userService.getUserByLogin(login) == null) {
+        logger.debug("User " + login + " does not exist. Creating");
+        user = new User();
+        user.setCryptedPassword(passwordEncoder.encode(passwd));
+        user.setLogin(login);
+        userService.addUser(user);
+      }
+      if (project != null) {
+        logger.debug("Privileges for " + login + " for project " + project.getProjectId());
+        ObjectPrivilege privilege = new ObjectPrivilege(project, 1, PrivilegeType.VIEW_PROJECT, user);
+        userService.setUserPrivilege(user, privilege);
+        if (admin) {
+          privilege = new ObjectPrivilege(project, 1, PrivilegeType.LAYOUT_MANAGEMENT, user);
+          userService.setUserPrivilege(user, privilege);
+          privilege = new ObjectPrivilege(project, 1, PrivilegeType.EDIT_COMMENTS_PROJECT, user);
+          userService.setUserPrivilege(user, privilege);
+        }
+
+      }
+    }
+  }
+
+  /**
+   * This method creates set of images for the model layouts.
+   * 
+   * @param originalModel
+   *          model for which we create layout images
+   * @param params
+   *          configuration parameters including set of layouts to generate
+   * @throws IOException
+   *           thrown when there are problems with generating files
+   * @throws DrawingException
+   *           thrown when there was a problem with drawing a map
+   * @throws CommandExecutionException
+   *           thrown when one of the files describing layouts is invalid
+   */
+  protected void createImages(final Model originalModel, final CreateProjectParams params)
+      throws IOException, DrawingException, CommandExecutionException {
+    if (!params.isImages()) {
+      return;
+    }
+    updateProjectStatus(originalModel.getProject(), ProjectStatus.GENERATING_IMAGES, 0, params);
+
+    List<Model> models = new ArrayList<Model>();
+    models.add(originalModel);
+    int size = originalModel.getLayouts().size();
+    for (ModelSubmodelConnection connection : originalModel.getSubmodelConnections()) {
+      models.add(connection.getSubmodel().getModel());
+      size += connection.getSubmodel().getModel().getLayouts().size();
+    }
+    int counter = 0;
+    for (final Model model : models) {
+      for (int i = 0; i < model.getLayouts().size(); i++) {
+        Layout layout = model.getLayouts().get(i);
+        if (layout.getInputData() == null) {
+          final double imgCounter = counter;
+          final double finalSize = size;
+          IProgressUpdater updater = new IProgressUpdater() {
+            @Override
+            public void setProgress(double progress) {
+              updateProjectStatus(originalModel.getProject(), ProjectStatus.GENERATING_IMAGES,
+                  IProgressUpdater.MAX_PROGRESS * imgCounter / finalSize + progress / finalSize, params);
+            }
+          };
+
+          generateImagesForBuiltInOverlay(params, model, layout, updater);
+        }
+        counter++;
+      }
+    }
+  }
+
+  private void generateImagesForBuiltInOverlay(final CreateProjectParams params, final Model model, Layout layout,
+      IProgressUpdater updater) throws CommandExecutionException, IOException, DrawingException {
+    String directory = layout.getDirectory();
+    Model output = model;
+    if (layout.isHierarchicalView()) {
+      output = new CopyCommand(model).execute();
+      new SetFixedHierarchyLevelCommand(output, layout.getHierarchyViewLevel()).execute();
+    }
+    if (layout.getTitle().equals(BuildInLayout.CLEAN.getTitle())) {
+      output = new CopyCommand(model).execute();
+      new ClearColorModelCommand(output).execute();
+    }
+
+    MapGeneratorParams imgParams = generator.new MapGeneratorParams().directory(directory).sbgn(params.isSbgnFormat())
+        .nested(layout.isHierarchicalView()).updater(updater);
+    imgParams.model(output);
+    generator.generateMapImages(imgParams);
+  }
+
+  /**
+   * Creates project. Loads model from the input and run PostLoadModification.
+   * 
+   * @param params
+   *          params used to create model
+   * @param dbProject
+   *          project where the model should be placed
+   * @throws InvalidInputDataExecption
+   *           thrown when there is a problem with input file
+   */
+  protected void createModel(final CreateProjectParams params, Project dbProject) throws InvalidInputDataExecption {
+    ModelData modelData = modelDao.getLastModelForProjectIdentifier(params.getProjectId(), false);
+    if (modelData != null) {
+      throw new InvalidArgumentException("Model with the given name already exists");
+    }
+
+    final Project project = dbProject;
+    updateProjectStatus(project, ProjectStatus.PARSING_DATA, 0.0, params);
+
+    if (params.isComplex()) {
+      try {
+        Class<? extends IConverter> clazz = CellDesignerXmlParser.class;
+        if (params.getParser() != null) {
+          clazz = params.getParser().getClass();
+        }
+        ComplexZipConverter parser = new ComplexZipConverter(clazz);
+        ComplexZipConverterParams complexParams;
+        complexParams = new ComplexZipConverterParams().zipFile(params.getProjectFile());
+        complexParams.visualizationDir(params.getProjectDir());
+        for (ZipEntryFile entry : params.getZipEntries()) {
+          complexParams.entry(entry);
+        }
+        ProjectFactory projectFactory = new ProjectFactory(parser);
+        projectFactory.create(complexParams, dbProject);
+      } catch (IOException e) {
+        throw new InvalidInputDataExecption(e);
+      }
+    } else {
+      IConverter parser;
+      if (params.getParser() != null) {
+        parser = params.getParser();
+      } else if (params.getProjectFile().endsWith("sbgn")) {
+        parser = new SbgnmlXmlConverter();
+      } else {
+        parser = new CellDesignerXmlParser();
+      }
+      try {
+        Model model = parser.createModel(new ConverterParams().filename(params.getProjectFile())
+            .sizeAutoAdjust(params.isAutoResize()).sbgnFormat(params.isSbgnFormat()));
+        model.setName(params.getProjectName());
+        project.addModel(model);
+      } catch (FileNotFoundException ex) {
+        throw new InvalidInputDataExecption(ex);
+      }
+    }
+    Model topModel = project.getModels().iterator().next().getModel();
+    topModel.setZoomLevels(generator.computeZoomLevels(topModel));
+    topModel.setTileSize(MapGenerator.TILE_SIZE);
+    dbProject.setNotifyEmail(params.getNotifyEmail());
+
+    updateProjectStatus(project, ProjectStatus.UPLOADING_TO_DB, 0.0, params);
+    dbUtils.setAutoFlush(false);
+    projectDao.update(project);
+    dbUtils.setAutoFlush(true);
+    projectDao.flush();
+
+    List<BuildInLayout> buildInLayouts = new ArrayList<>();
+    BuildInLayout nested = null;
+    if (params.isSemanticZoom()) {
+      nested = BuildInLayout.SEMANTIC;
+    } else {
+      nested = BuildInLayout.NESTED;
+    }
+    if (params.isNetworkLayoutAsDefault()) {
+      buildInLayouts.add(BuildInLayout.NORMAL);
+      buildInLayouts.add(nested);
+    } else {
+      buildInLayouts.add(nested);
+      buildInLayouts.add(BuildInLayout.NORMAL);
+    }
+    buildInLayouts.add(BuildInLayout.CLEAN);
+
+    // reverse the order of build in layouts, so we can insert them at the
+    // beginning of list of layouts (the order will be the same)
+    Collections.reverse(buildInLayouts);
+
+    for (BuildInLayout buildInLayout : buildInLayouts) {
+      Layout topLayout = new Layout(buildInLayout.getTitle(),
+          params.getProjectDir() + "/" + buildInLayout.getDirectorySuffix() + topModel.getId() + "/", true);
+      topLayout.setStatus(LayoutStatus.NA);
+      topLayout.setProgress(0.0);
+      topLayout.setHierarchicalView(buildInLayout.isNested());
+      topModel.addLayout(0, topLayout);
+      int submodelId = 1;
+      List<Layout> semanticLevelOverlays = new ArrayList<>();
+      if (buildInLayout.equals(BuildInLayout.SEMANTIC)) {
+        for (int i = 0; i <= topModel.getZoomLevels(); i++) {
+          String directory = params.getProjectDir() + "/" + buildInLayout.getDirectorySuffix() + "-" + i + "-"
+              + topModel.getId() + "/";
+          Layout semanticOverlay = new Layout(buildInLayout.getTitle() + "-" + i, directory, true);
+          semanticOverlay.setStatus(LayoutStatus.NA);
+          semanticOverlay.setProgress(0.0);
+          semanticOverlay.setHierarchicalView(buildInLayout.isNested());
+          semanticOverlay.setHierarchyViewLevel(i);
+          semanticLevelOverlays.add(semanticOverlay);
+          topModel.addLayout(1, semanticOverlay);
+        }
+      }
+      for (ModelSubmodelConnection connection : topModel.getSubmodelConnections()) {
+        Layout layout = new Layout(buildInLayout.getTitle(),
+            params.getProjectDir() + "/" + buildInLayout.getDirectorySuffix() + submodelId + "/", true);
+        layout.setStatus(LayoutStatus.NA);
+        layout.setProgress(0.0);
+        layout.setHierarchicalView(buildInLayout.isNested());
+        layout.setParentLayout(topLayout);
+        connection.getSubmodel().addLayout(0, layout);
+
+        connection.getSubmodel().setZoomLevels(generator.computeZoomLevels(connection.getSubmodel().getModel()));
+        connection.getSubmodel().setTileSize(MapGenerator.TILE_SIZE);
+        if (buildInLayout.equals(BuildInLayout.SEMANTIC)) {
+          for (int i = 0; i <= topModel.getZoomLevels(); i++) {
+            String directory = params.getProjectDir() + "/" + buildInLayout.getDirectorySuffix() + "-" + i + "-"
+                + submodelId + "/";
+            Layout semanticOverlay = new Layout(buildInLayout.getTitle() + "-" + i, directory, true);
+            semanticOverlay.setStatus(LayoutStatus.NA);
+            semanticOverlay.setProgress(0.0);
+            semanticOverlay.setHierarchicalView(buildInLayout.isNested());
+            semanticOverlay.setParentLayout(semanticLevelOverlays.get(i));
+            semanticOverlay.setHierarchyViewLevel(i);
+            connection.getSubmodel().addLayout(1, semanticOverlay);
+          }
+        }
+        submodelId++;
+      }
+    }
+
+    if (params.isUpdateAnnotations()) {
+      Map<Class<?>, List<ElementAnnotator>> annotators = null;
+      if (params.getAnnotatorsMap() != null) {
+        annotators = new HashMap<Class<?>, List<ElementAnnotator>>();
+        for (Class<?> clazz : params.getAnnotatorsMap().keySet()) {
+          annotators.put(clazz, modelAnnotator.getAnnotatorsFromCommonNames(params.getAnnotatorsMap().get(clazz)));
+        }
+      }
+      logger.debug("Updating annotations");
+      modelAnnotator.performAnnotations(topModel, new IProgressUpdater() {
+
+        @Override
+        public void setProgress(final double progress) {
+          updateProjectStatus(project, ProjectStatus.ANNOTATING, progress, params);
+        }
+      }, annotators);
+      logger.debug("Annotations updated");
+    }
+    updateProjectStatus(project, ProjectStatus.EXTENDING_MODEL, 0.0, params);
+    processDataMining(topModel, topModel.getDataMiningSets(), new IProgressUpdater() {
+
+      @Override
+      public void setProgress(double progress) {
+        updateProjectStatus(project, ProjectStatus.EXTENDING_MODEL, progress, params);
+      }
+
+    });
+    updateProjectStatus(project, ProjectStatus.EXTENDING_MODEL, IProgressUpdater.MAX_PROGRESS, params);
+    logger.debug("Model created");
+
+  }
+
+  /**
+   * Process data mining files and assign suggested connections to the model.
+   * 
+   * @param model
+   *          model where the suggested connections will be added
+   * @param dataMiningSets
+   *          set of files to process
+   * @param progressUpdater
+   *          callback function informing higher layer about progress
+   * @throws InvalidDataMiningInputFile
+   *           thrown when one of the files is invalid
+   */
+  private void processDataMining(Model model, List<DataMiningSet> dataMiningSets,
+      final IProgressUpdater progressUpdater) throws InvalidDataMiningInputFile {
+    Set<Element> nodes = new HashSet<>();
+    nodes.addAll(model.getElements());
+    for (ModelSubmodelConnection connection : model.getSubmodelConnections()) {
+      nodes.addAll(connection.getSubmodel().getElements());
+    }
+    Set<Reaction> reactions = new HashSet<Reaction>();
+    reactions.addAll(model.getReactions());
+    for (ModelSubmodelConnection connection : model.getSubmodelConnections()) {
+      reactions.addAll(connection.getSubmodel().getReactions());
+    }
+
+    int fileCounter = 0;
+    final int filesCount = dataMiningSets.size();
+    for (DataMiningSet dmSet : dataMiningSets) {
+
+      final double offset = IProgressUpdater.MAX_PROGRESS * fileCounter / filesCount;
+      IProgressUpdater secondPartUpdater = new IProgressUpdater() {
+
+        @Override
+        public void setProgress(double progress) {
+          progressUpdater.setProgress((progress * CREATION_OF_DATA) / ((double) filesCount) + offset);
+        }
+      };
+      Set<DataMining> result = dataMiningService.parseData(dmSet, nodes, reactions, secondPartUpdater);
+      double size = result.size();
+      double count = 0;
+
+      double updateOffset = IProgressUpdater.MAX_PROGRESS * fileCounter / filesCount
+          + CREATION_OF_DATA / ((double) filesCount);
+      for (DataMining missingConnection : result) {
+        missingConnection.setType(dmSet.getType());
+        missingConnection.getElement().addDataMining(missingConnection);
+        count++;
+        progressUpdater.setProgress(updateOffset + IProgressUpdater.MAX_PROGRESS * count / size * UPLOAD_OF_DATA);
+      }
+    }
+  }
+
+  /**
+   * Updates status of the generating project.
+   * 
+   * @param project
+   *          project that is generated
+   * @param status
+   *          what is the current status
+   * @param progress
+   *          what is the progress
+   * @param params
+   *          parameters used for project creation
+   */
+  private void updateProjectStatus(Project project, ProjectStatus status, double progress, CreateProjectParams params) {
+    if (project != null) {
+      if (!status.equals(project.getStatus())
+          || (Math.abs(progress - project.getProgress()) > IProgressUpdater.PROGRESS_BAR_UPDATE_RESOLUTION)) {
+        project.setStatus(status);
+        project.setProgress(progress);
+        projectDao.update(project);
+        if (params.isAsync()) {
+          projectDao.commit();
+        }
+      }
+    } else {
+      logger.debug("status: " + status + ", " + progress);
+    }
+  }
+
+  @Override
+  public void createProject(final CreateProjectParams params) throws SecurityException {
+    if (!userService.userHasPrivilege(params.getAuthenticationToken(), PrivilegeType.ADD_MAP)) {
+      throw new SecurityException("Adding projects not allowed.");
+    }
+
+    // this count down is used to wait for asynchronous thread to initialize
+    // data in the db (probably it would be better to move the initialization to
+    // main thread)
+    final CountDownLatch waitForInitialData = new CountDownLatch(1);
+
+    Thread computations = new Thread(new Runnable() {
+
+      @Override
+      public void run() {
+        if (params.isAsync()) {
+          // because we are running this in separate thread we need to open a
+          // new session for db connection
+          dbUtils.createSessionForCurrentThread();
+        }
+
+        Project project = new Project();
+        project.setProjectId(params.getProjectId());
+        project.setName(params.getProjectName());
+        if (params.getProjectDir() == null) {
+          logger.warn("Project directory not set");
+          project.setDirectory(null);
+        } else {
+          project.setDirectory(new File(params.getProjectDir()).getName());
+        }
+        project.setSbgnFormat(params.isSbgnFormat());
+
+        MiriamData disease = null;
+        if (params.getDisease() != null && !params.getDisease().isEmpty()) {
+          disease = new MiriamData(MiriamType.MESH_2012, params.getDisease());
+        }
+        MiriamData organism = null;
+        if (params.getOrganism() != null && !params.getOrganism().isEmpty()) {
+          organism = new MiriamData(MiriamType.TAXONOMY, params.getOrganism());
+        }
+        project.setVersion(params.getVersion());
+        projectDao.add(project);
+        if (params.isAsync()) {
+          projectDao.commit();
+        }
+        waitForInitialData.countDown();
+        double[] outOfMemoryBuffer;
+        EventStorageLoggerAppender appender = new EventStorageLoggerAppender();
+        try {
+          Logger.getRootLogger().addAppender(appender);
+          logger.debug("Running: " + params.getProjectId() + "; " + params.getProjectFile());
+          outOfMemoryBuffer = new double[OUT_OF_MEMORY_BACKUP_BUFFER_SIZE];
+          for (int i = 0; i < OUT_OF_MEMORY_BACKUP_BUFFER_SIZE; i++) {
+            outOfMemoryBuffer[i] = Math.random() * OUT_OF_MEMORY_BACKUP_BUFFER_SIZE;
+          }
+
+          File inputFile = new File(params.getProjectFile());
+          if (inputFile.exists()) {
+            UploadedFileEntry file = new UploadedFileEntry();
+            file.setFileContent(IOUtils.toByteArray(new FileInputStream(inputFile)));
+            file.setOriginalFileName(FilenameUtils.getName(params.getProjectFile()));
+            file.setLength(file.getFileContent().length);
+            User owner = null;
+            for (String[] userRow : params.getUsers()) {
+              User user = userService.getUserByLogin(userRow[0]);
+              if (user != null) {
+                owner = user;
+              }
+            }
+            file.setOwner(owner);
+            project.setInputData(file);
+          }
+
+          createModel(params, project);
+          Model originalModel = project.getModels().iterator().next().getModel();
+          if (!params.isSemanticZoom()) {
+            new CreateHierarchyCommand(originalModel, generator.computeZoomLevels(originalModel),
+                generator.computeZoomFactor(originalModel)).execute();
+          }
+
+          addUsers(project, params);
+          createImages(originalModel, params);
+
+          for (Layout layout : originalModel.getLayouts()) {
+            String[] tmp = layout.getDirectory().split("[\\\\/]");
+            layout.setDirectory(tmp[tmp.length - 1]);
+          }
+          for (ModelSubmodelConnection connection : originalModel.getSubmodelConnections()) {
+            for (Layout layout : connection.getSubmodel().getLayouts()) {
+              String[] tmp = layout.getDirectory().split("[\\\\/]");
+              layout.setDirectory(tmp[tmp.length - 1]);
+            }
+          }
+
+          try {
+            if (meshParser.isValidMeshId(disease)) {
+              project.setDisease(disease);
+            } else {
+              logger.warn("No valid disease is provided for project:" + project.getName());
+            }
+          } catch (AnnotatorException e1) {
+            logger.warn("Problem with accessing mesh db. More info in logs.");
+          }
+
+          if (taxonomyBackend.getNameForTaxonomy(organism) != null) {
+            project.setOrganism(organism);
+          } else {
+            logger.warn("No valid organism is provided for project:" + project.getName());
+          }
+
+          modelDao.update(originalModel);
+
+          if (params.isCacheModel()) {
+            cacheData(originalModel, params);
+          }
+
+          if (params.isAnalyzeAnnotations()) {
+            analyzeAnnotations(originalModel, params);
+          }
+          Logger.getRootLogger().removeAppender(appender);
+          project.addLoggingInfo(appender);
+          updateProjectStatus(project, ProjectStatus.DONE, IProgressUpdater.MAX_PROGRESS, params);
+          if (project.getNotifyEmail() != null && !project.getNotifyEmail().equals("")) {
+            try {
+              sendSuccesfullEmail(originalModel);
+            } catch (MessagingException e) {
+              logger.error(e, e);
+            }
+          }
+
+          LogParams params = new LogParams().description("Created successfully").type(LogType.MAP_CREATED)
+              .object(originalModel);
+          logService.log(params);
+
+        } catch (HibernateException e) {
+          outOfMemoryBuffer = null;
+          logger.error("Problem with database", e);
+          handleHibernateExceptionReporting(params, e);
+        } catch (Exception e) {
+          outOfMemoryBuffer = null;
+          handleCreateProjectException(params, e);
+        } catch (OutOfMemoryError oome) {
+          // release some memory
+          outOfMemoryBuffer = null;
+          logger.error("Out of memory", oome);
+          if (project != null) {
+            project.setErrors("Out of memory: " + oome.getMessage());
+          }
+          updateProjectStatus(project, ProjectStatus.FAIL, IProgressUpdater.MAX_PROGRESS, params);
+        } finally {
+          if (params.isAsync()) {
+            // close the transaction for this thread
+            dbUtils.closeSessionForCurrentThread();
+          }
+          Logger.getRootLogger().removeAppender(appender);
+        }
+      }
+    });
+    if (params.isAsync()) {
+      computations.start();
+    } else {
+      computations.run();
+    }
+
+    try {
+      waitForInitialData.await();
+    } catch (InterruptedException e1) {
+      logger.error(e1, e1);
+    }
+
+  }
+
+  /**
+   * Cache pubmed data for the model.
+   * 
+   * @param originalModel
+   *          model for which we want to cache data.
+   * @param params
+   *          parameters used for model generation
+   */
+  private void cacheData(final Model originalModel, final CreateProjectParams params) {
+    modelService.cacheAllPubmedIds(originalModel, new IProgressUpdater() {
+      @Override
+      public void setProgress(double progress) {
+        updateProjectStatus(originalModel.getProject(), ProjectStatus.CACHING, progress, params);
+      }
+    });
+    modelService.cacheAllMiriamLinks(originalModel, new IProgressUpdater() {
+      @Override
+      public void setProgress(double progress) {
+        updateProjectStatus(originalModel.getProject(), ProjectStatus.CACHING_MIRIAM, progress, params);
+      }
+    });
+
+    chemicalService.cacheDataForModel(originalModel, new IProgressUpdater() {
+      @Override
+      public void setProgress(double progress) {
+        updateProjectStatus(originalModel.getProject(), ProjectStatus.CACHING_CHEMICAL, progress, params);
+      }
+    });
+
+    drugService.cacheDataForModel(originalModel, new IProgressUpdater() {
+      @Override
+      public void setProgress(double progress) {
+        updateProjectStatus(originalModel.getProject(), ProjectStatus.CACHING_DRUG, progress, params);
+      }
+    });
+
+    mirnaService.cacheDataForModel(originalModel, new IProgressUpdater() {
+      @Override
+      public void setProgress(double progress) {
+        updateProjectStatus(originalModel.getProject(), ProjectStatus.CACHING_MI_RNA, progress, params);
+      }
+    });
+
+  }
+
+  /**
+   * @return the modelDao
+   * @see #modelDao
+   */
+  public ModelDao getModelDao() {
+    return modelDao;
+  }
+
+  /**
+   * @param modelDao
+   *          the modelDao to set
+   * @see #modelDao
+   */
+  public void setModelDao(ModelDao modelDao) {
+    this.modelDao = modelDao;
+  }
+
+  /**
+   * @return the commentService
+   * @see #commentService
+   */
+  public ICommentService getCommentService() {
+    return commentService;
+  }
+
+  /**
+   * @param commentService
+   *          the commentService to set
+   * @see #commentService
+   */
+  public void setCommentService(ICommentService commentService) {
+    this.commentService = commentService;
+  }
+
+  /**
+   * @return the passwordEncoder
+   * @see #passwordEncoder
+   */
+  public PasswordEncoder getPasswordEncoder() {
+    return passwordEncoder;
+  }
+
+  /**
+   * @param passwordEncoder
+   *          the passwordEncoder to set
+   * @see #passwordEncoder
+   */
+  public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
+    this.passwordEncoder = passwordEncoder;
+  }
+
+  /**
+   * @return the commentDao
+   * @see #commentDao
+   */
+  public CommentDao getCommentDao() {
+    return commentDao;
+  }
+
+  /**
+   * @param commentDao
+   *          the commentDao to set
+   * @see #commentDao
+   */
+  public void setCommentDao(CommentDao commentDao) {
+    this.commentDao = commentDao;
+  }
+
+  /**
+   * @return the modelAnnotator
+   * @see #modelAnnotator
+   */
+  public ModelAnnotator getModelAnnotator() {
+    return modelAnnotator;
+  }
+
+  /**
+   * @param modelAnnotator
+   *          the modelAnnotator to set
+   * @see #modelAnnotator
+   */
+  public void setModelAnnotator(ModelAnnotator modelAnnotator) {
+    this.modelAnnotator = modelAnnotator;
+  }
+
+  /**
+   * @return the dbUtils
+   * @see #dbUtils
+   */
+  public DbUtils getDbUtils() {
+    return dbUtils;
+  }
+
+  /**
+   * @param dbUtils
+   *          the dbUtils to set
+   * @see #dbUtils
+   */
+  public void setDbUtils(DbUtils dbUtils) {
+    this.dbUtils = dbUtils;
+  }
+
+  /**
+   * @return the projectDao
+   * @see #projectDao
+   */
+  public ProjectDao getProjectDao() {
+    return projectDao;
+  }
+
+  /**
+   * @param projectDao
+   *          the projectDao to set
+   * @see #projectDao
+   */
+  public void setProjectDao(ProjectDao projectDao) {
+    this.projectDao = projectDao;
+  }
+
+  /**
+   * @return the dataMiningService
+   * @see #dataMiningService
+   */
+  public IDataMiningService getDataMiningService() {
+    return dataMiningService;
+  }
+
+  /**
+   * @param dataMiningService
+   *          the dataMiningService to set
+   * @see #dataMiningService
+   */
+  public void setDataMiningService(IDataMiningService dataMiningService) {
+    this.dataMiningService = dataMiningService;
+  }
+
+  @Override
+  public ProjectView createEmpty() {
+    return projectViewFactory.create(null);
+  }
+
+  /**
+   * Analyzes annotation of the model and put information about invalid
+   * annotations into the {@link Model#creationWarnings} field.
+   * 
+   * @param originalModel
+   *          model to analyze
+   * @param params
+   *          parameters used for model generation
+   */
+  protected void analyzeAnnotations(final Model originalModel, final CreateProjectParams params) {
+    logger.debug("Analyze annotations");
+    Collection<? extends ProblematicAnnotation> improperAnnotations = modelAnnotator
+        .findImproperAnnotations(originalModel, new IProgressUpdater() {
+
+          @Override
+          public void setProgress(double progress) {
+            updateProjectStatus(originalModel.getProject(), ProjectStatus.VALIDATING_MIRIAM, progress, params);
+          }
+        }, params.getValidAnnotations());
+    List<String> res = new ArrayList<>();
+    for (ProblematicAnnotation improperAnnotation : improperAnnotations) {
+      res.add(improperAnnotation.toString());
+    }
+    Collections.sort(res);
+
+    Collection<? extends ProblematicAnnotation> missingAnnotations = modelAnnotator
+        .findMissingAnnotations(originalModel, params.getRequiredAnnotations());
+    for (ProblematicAnnotation improperAnnotation : missingAnnotations) {
+      res.add(improperAnnotation.toString());
+    }
+    for (String message : res) {
+      logger.warn(message);
+    }
+    logger.debug("Analyze finished");
+  }
+
+  /**
+   * Sends notification email that map was removed.
+   * 
+   * @param projectId
+   *          identifier of the project
+   * @param email
+   *          otification email
+   * @throws MessagingException
+   *           thrown when there is a problem with sending email
+   */
+  protected void sendSuccesfullRemoveEmail(String projectId, String email) throws MessagingException {
+    EmailSender emailSender = new EmailSender(configurationService);
+    StringBuilder content = new StringBuilder("Map " + projectId + " was successfully removed.<br/>");
+    emailSender.sendEmail("MapViewer notification", content.toString(), email);
+  }
+
+  @Override
+  public TreeNode createClassAnnotatorTree(User user) {
+
+    UserAnnotationSchema annotationSchema = prepareUserAnnotationSchema(user);
+
+    ElementUtils elementUtils = new ElementUtils();
+
+    ClassTreeNode top = elementUtils.getAnnotatedElementClassTree();
+
+    Class<?> clazz = top.getClazz();
+    TreeNode root = new DefaultTreeNode(new AnnotatedObjectTreeRow(top, modelAnnotator.getAvailableAnnotators(clazz),
+        modelAnnotator.getAnnotatorsFromCommonNames(annotationSchema.getAnnotatorsForClass(clazz)),
+        annotationSchema.getValidAnnotations(clazz), annotationSchema.getRequiredAnnotations(clazz)), null);
+
+    root.setExpanded(true);
+
+    Queue<Pair<ClassTreeNode, TreeNode>> nodes = new LinkedList<Pair<ClassTreeNode, TreeNode>>();
+    nodes.add(new Pair<ClassTreeNode, TreeNode>(top, root));
+    // create children
+
+    Queue<TreeNode> expandParents = new LinkedList<TreeNode>();
+
+    while (!nodes.isEmpty()) {
+      Pair<ClassTreeNode, TreeNode> element = nodes.poll();
+
+      for (ClassTreeNode node : element.getLeft().getChildren()) {
+
+        clazz = node.getClazz();
+        AnnotatedObjectTreeRow data = new AnnotatedObjectTreeRow(node, modelAnnotator.getAvailableAnnotators(clazz),
+            modelAnnotator.getAnnotatorsFromCommonNames(annotationSchema.getAnnotatorsForClass(clazz)),
+            annotationSchema.getValidAnnotations(clazz), annotationSchema.getRequiredAnnotations(clazz));
+        TreeNode treeNode = new DefaultTreeNode(data, element.getRight());
+        nodes.add(new Pair<ClassTreeNode, TreeNode>(node, treeNode));
+        if (data.getUsedAnnotators().size() > 0 || data.getValidAnnotators().size() > 0) {
+          expandParents.add(treeNode);
+        }
+      }
+    }
+    while (!expandParents.isEmpty()) {
+      TreeNode node = expandParents.poll();
+      if (node.getParent() != null && !node.getParent().isExpanded()) {
+        node.getParent().setExpanded(true);
+        expandParents.add(node.getParent());
+      }
+    }
+
+    return root;
+
+  }
+
+  /**
+   * Retrieves (or creates) annotation schema for a given user.
+   * 
+   * @param user
+   *          for this users {@link UserAnnotationSchema} will be prepared
+   * @return {@link UserAnnotationSchema} for {@link User}
+   */
+  public UserAnnotationSchema prepareUserAnnotationSchema(User user) {
+    UserAnnotationSchema annotationSchema = null;
+    if (user != null) {
+      annotationSchema = userDao.getById(user.getId()).getAnnotationSchema();
+    }
+    if (annotationSchema == null) {
+      annotationSchema = new UserAnnotationSchema();
+
+      ElementUtils elementUtils = new ElementUtils();
+
+      ClassTreeNode top = elementUtils.getAnnotatedElementClassTree();
+
+      Map<Class<? extends BioEntity>, Set<MiriamType>> validMiriam = modelAnnotator.getDefaultValidClasses();
+      Map<Class<? extends BioEntity>, Set<MiriamType>> requiredMiriam = modelAnnotator.getDefaultRequiredClasses();
+
+      Queue<ClassTreeNode> nodes = new LinkedList<ClassTreeNode>();
+      nodes.add(top);
+
+      while (!nodes.isEmpty()) {
+        ClassTreeNode element = nodes.poll();
+        annotationSchema.addClassAnnotator(new UserClassAnnotators(element.getClazz(),
+            modelAnnotator.getAvailableDefaultAnnotatorNames(element.getClazz())));
+        annotationSchema.addClassValidAnnotations(
+            new UserClassValidAnnotations(element.getClazz(), validMiriam.get(element.getClazz())));
+        annotationSchema.addClassRequiredAnnotations(
+            new UserClassRequiredAnnotations(element.getClazz(), requiredMiriam.get(element.getClazz())));
+        for (ClassTreeNode node : element.getChildren()) {
+          nodes.add(node);
+        }
+      }
+      User dbUser = userDao.getById(user.getId());
+      dbUser.setAnnotationSchema(annotationSchema);
+      userDao.update(dbUser);
+    }
+    return annotationSchema;
+  }
+
+  @Override
+  public void updateClassAnnotatorTreeForUser(User user, TreeNode annotatorsTree, boolean sbgnFormat,
+      boolean networkLayoutAsDefault) {
+    User dbUser = userDao.getById(user.getId());
+    if (dbUser.getAnnotationSchema() == null) {
+      dbUser.setAnnotationSchema(new UserAnnotationSchema());
+    }
+    UserAnnotationSchema annotationSchema = dbUser.getAnnotationSchema();
+
+    Queue<TreeNode> queue = new LinkedList<TreeNode>();
+    queue.add(annotatorsTree);
+    while (!queue.isEmpty()) {
+      TreeNode node = queue.poll();
+      for (TreeNode child : node.getChildren()) {
+        queue.add(child);
+      }
+      AnnotatedObjectTreeRow data = (AnnotatedObjectTreeRow) node.getData();
+      annotationSchema.addClassAnnotator(new UserClassAnnotators(data.getClazz(), data.getUsedAnnotators()));
+      annotationSchema.addClassRequiredAnnotations(
+          new UserClassRequiredAnnotations(data.getClazz(), data.getRequiredAnnotations()));
+      annotationSchema
+          .addClassValidAnnotations(new UserClassValidAnnotations(data.getClazz(), data.getValidAnnotations()));
+    }
+    annotationSchema.setSbgnFormat(sbgnFormat);
+    annotationSchema.setNetworkLayoutAsDefault(networkLayoutAsDefault);
+    userService.updateUser(dbUser);
+    user.setAnnotationSchema(annotationSchema);
+  }
+
+  /**
+   * Sends email about unsuccessfull project creation.
+   * 
+   * @param projectName
+   *          name of the project
+   * @param email
+   *          email where we want to send information
+   * @param e
+   *          exception that caused problem
+   */
+  private void sendUnsuccesfullEmail(String projectName, String email, Exception e) {
+    EmailSender emailSender = new EmailSender(configurationService);
+    StringBuilder content = new StringBuilder("");
+    content.append("There was a problem with generating " + projectName + " map.<br/>");
+    content.append(e.getClass().getName() + ": " + e.getMessage());
+    try {
+      emailSender.sendEmail("MapViewer notification", content.toString(), email);
+    } catch (MessagingException e1) {
+      logger.error(e1);
+    }
+  }
+
+  /**
+   * Sends email about successfull project creation.
+   * 
+   * @param originalModel
+   *          model that was created
+   * @throws MessagingException
+   *           exception thrown when there is a problem with sending email
+   */
+  protected void sendSuccesfullEmail(Model originalModel) throws MessagingException {
+    EmailSender emailSender = new EmailSender(configurationService);
+    StringBuilder content = new StringBuilder("Your map was generated successfully.<br/>");
+    emailSender.sendEmail("MapViewer notification", content.toString(), originalModel.getProject().getNotifyEmail());
+  }
+
+  @Override
+  public void updateProject(Project project) {
+    projectDao.update(project);
+  }
+
+  /**
+   * This method handles situation when sever db error appeard during uploading of
+   * the project into database.
+   * 
+   * @param params
+   *          parameters used to create project
+   * @param e
+   *          exception that occured during uploading of the project
+   */
+  private void handleHibernateExceptionReporting(CreateProjectParams params, HibernateException e) {
+    // we need to open separate thread because current one thrown db exception
+    // and transaction is corrupetd and will be rolledback
+    Thread reportInSeparateThread = new Thread(new Runnable() {
+
+      @Override
+      public void run() {
+        dbUtils.createSessionForCurrentThread();
+
+        try {
+          Project project = getProjectByProjectId(params.getProjectId(), params.getAuthenticationToken());
+          String errorMessage = "Problem with uploading to database. "
+              + "You might violated some unhandled constraints or you run out of memory. Underlaying eror:\n"
+              + e.getMessage() + "\nMore information can be found in log file.";
+          project.setErrors(errorMessage);
+          project.setStatus(ProjectStatus.FAIL);
+          projectDao.update(project);
+        } catch (Exception e) {
+          logger.error(e, e);
+        } finally {
+          dbUtils.closeSessionForCurrentThread();
+        }
+      }
+
+    });
+    reportInSeparateThread.start();
+
+  }
+
+  @Override
+  public byte[] getInputDataForProject(ProjectView projectView) {
+    return getInputDataForProject(projectView.getIdObject());
+  }
+
+  /**
+   * Returns byte array containing data from original input file that was used to
+   * create this project.
+   * 
+   * @param projectId
+   *          identifier of project for which we want to retrieve original file
+   *          data
+   * @return original data file for given layout, if such file is not stored in
+   *         database (compatibility reasons) then null is returned
+   */
+  private byte[] getInputDataForProject(int projectId) {
+    Project project = projectDao.getById(projectId);
+    if (project == null || project.getInputData() == null) {
+      return null;
+    } else {
+      return project.getInputData().getFileContent();
+    }
+  }
+
+  /**
+   * Method that handles exception reporting during creation of a project.
+   * 
+   * @param params
+   *          set of parameters used to create project
+   * @param e
+   *          exception that caused problems
+   */
+  private void handleCreateProjectException(final CreateProjectParams params, Exception e) {
+    Project p = projectDao.getProjectByProjectId(params.getProjectId());
+    logger.error(e.getMessage(), e);
+    if (p != null) {
+      p.setErrors("Problem with uploading map: " + e.getMessage() + ". More details can be found in log file.");
+    }
+    updateProjectStatus(p, ProjectStatus.FAIL, IProgressUpdater.MAX_PROGRESS, params);
+
+    String email = params.getNotifyEmail();
+    String projectName = params.getProjectId();
+
+    LogParams logParams = new LogParams().description("Failed: " + e.getMessage()).type(LogType.MAP_CREATED).object(p);
+    logService.log(logParams);
+    if (email != null) {
+      sendUnsuccesfullEmail(projectName, email, e);
+    }
+  }
+
+  /**
+   * @return the taxonomyBackend
+   * @see #taxonomyBackend
+   */
+  public TaxonomyBackend getTaxonomyBackend() {
+    return taxonomyBackend;
+  }
+
+  /**
+   * @param taxonomyBackend
+   *          the taxonomyBackend to set
+   * @see #taxonomyBackend
+   */
+  public void setTaxonomyBackend(TaxonomyBackend taxonomyBackend) {
+    this.taxonomyBackend = taxonomyBackend;
+  }
 
 }