diff --git a/.gitignore b/.gitignore
index bbcea90463b8d87b5fec80ccacfd75fdaa3587b7..5f2ce9bf39d3f4369734360f98a8e770780ca767 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,6 +10,7 @@ web/src/main/webapp/svnversion.txt
 /target/
 service/minerva-big/
 npm-debug.log
+converter-sbml/jsbml.log
 
 .idea/workspace.xml
 .idea/libraries/
diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlCompartmentParser.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlCompartmentParser.java
index 27cc67f3126ab3b670d497aeb02af8bcc2f2a573..9e119bfbaffaa72f7ad2b08d3636aa66e7ae074a 100644
--- a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlCompartmentParser.java
+++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlCompartmentParser.java
@@ -1,84 +1,32 @@
 package lcsb.mapviewer.converter.model.sbml;
 
 import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
-import java.util.Set;
 
 import javax.xml.stream.XMLStreamException;
 
 import org.apache.log4j.Logger;
-import org.sbml.jsbml.Annotation;
+import org.sbml.jsbml.ListOf;
 import org.sbml.jsbml.Model;
+import org.sbml.jsbml.ext.layout.AbstractReferenceGlyph;
 import org.sbml.jsbml.ext.layout.CompartmentGlyph;
 import org.sbml.jsbml.ext.layout.Layout;
-import org.sbml.jsbml.util.NotImplementedException;
 
+import lcsb.mapviewer.common.Pair;
 import lcsb.mapviewer.converter.InvalidInputDataExecption;
-import lcsb.mapviewer.model.map.MiriamData;
 import lcsb.mapviewer.model.map.compartment.Compartment;
 import lcsb.mapviewer.model.map.compartment.SquareCompartment;
 
-public class SbmlCompartmentParser {
+public class SbmlCompartmentParser extends SbmlElementParser<org.sbml.jsbml.Compartment> {
   Logger logger = Logger.getLogger(SbmlCompartmentParser.class);
 
-  Layout layout;
-
   public SbmlCompartmentParser(Layout layout) {
-    this.layout = layout;
-  }
-
-  public List<Compartment> parseList(Model sbmlModel) throws InvalidInputDataExecption {
-    List<Compartment> result = new ArrayList<>();
-    for (org.sbml.jsbml.Compartment compartment : sbmlModel.getListOfCompartments()) {
-      result.add(parse(compartment));
-    }
-    if (layout != null) {
-      return mergeLayout(result, layout);
-    } else {
-      return result;
-    }
-  }
-
-  private List<Compartment> mergeLayout(List<Compartment> compartments, Layout sbmlLayout)
-      throws InvalidInputDataExecption {
-    Set<Compartment> used = new HashSet<>();
-    Map<String, Compartment> compartmentById = new HashMap<>();
-    for (Compartment compartment : compartments) {
-      if (compartmentById.get(compartment.getElementId()) != null) {
-        throw new InvalidInputDataExecption("Duplicated element id: " + compartment.getElementId());
-      }
-      compartmentById.put(compartment.getElementId(), compartment);
-    }
-    List<Compartment> result = new ArrayList<>();
-
-    for (CompartmentGlyph glyph : sbmlLayout.getListOfCompartmentGlyphs()) {
-      Compartment source = compartmentById.get(glyph.getCompartment());
-      if (source==null) {
-        throw new InvalidInputDataExecption("Layout contains invalid compartment id: "+glyph.getCompartment());
-      }
-      used.add(source);
-      Compartment compartmentWithLayout = new SquareCompartment(source);
-      compartmentWithLayout.setElementId(glyph.getId());
-      compartmentWithLayout.setX(glyph.getBoundingBox().getPosition().getX());
-      compartmentWithLayout.setY(glyph.getBoundingBox().getPosition().getY());
-      compartmentWithLayout.setWidth(glyph.getBoundingBox().getDimensions().getWidth());
-      compartmentWithLayout.setHeight(glyph.getBoundingBox().getDimensions().getHeight());
-      result.add(compartmentWithLayout);
-    }
-    for (Compartment compartment : compartments) {
-      if (!used.contains(compartment)) {
-        logger.warn("Layout doesn't contain information about compartment: "+compartment.getElementId());
-        result.add(compartment);
-      }
-    }
-    return result;
+    super(layout);
   }
 
-  private Compartment parse(org.sbml.jsbml.Compartment compartment) throws InvalidInputDataExecption {
-    Compartment result = new Compartment(compartment.getId());
+  @Override
+  protected Compartment parse(org.sbml.jsbml.Compartment compartment) throws InvalidInputDataExecption {
+    Compartment result = new SquareCompartment(compartment.getId());
     result.setMiriamData(parseAnnotation(compartment.getAnnotation()));
     result.setName(compartment.getName());
     try {
@@ -89,11 +37,17 @@ public class SbmlCompartmentParser {
     return result;
   }
 
-  protected Set<MiriamData> parseAnnotation(Annotation annotation) {
-    if (annotation.getCVTermCount() > 0) {
-      throw new NotImplementedException();
+  @Override
+  protected ListOf<org.sbml.jsbml.Compartment> getSbmlElementList(Model sbmlModel) {
+    return sbmlModel.getListOfCompartments();
+  }
+
+  @Override
+  protected List<Pair<String, AbstractReferenceGlyph>> getGlyphs(Layout sbmlLayout) {
+    List<Pair<String, AbstractReferenceGlyph>> result = new ArrayList<>();
+    for (CompartmentGlyph glyph : sbmlLayout.getListOfCompartmentGlyphs()) {
+      result.add(new Pair<String, AbstractReferenceGlyph>(glyph.getCompartment(), glyph));
     }
-    Set<MiriamData> result = new HashSet<>();
     return result;
   }
 
diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlElementParser.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlElementParser.java
new file mode 100644
index 0000000000000000000000000000000000000000..5b7c7edcb98e8b050fb3f0aca830347bd81dd201
--- /dev/null
+++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlElementParser.java
@@ -0,0 +1,94 @@
+package lcsb.mapviewer.converter.model.sbml;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.log4j.Logger;
+import org.sbml.jsbml.Annotation;
+import org.sbml.jsbml.ListOf;
+import org.sbml.jsbml.Model;
+import org.sbml.jsbml.ext.layout.AbstractReferenceGlyph;
+import org.sbml.jsbml.ext.layout.Layout;
+import org.sbml.jsbml.util.NotImplementedException;
+
+import lcsb.mapviewer.common.Pair;
+import lcsb.mapviewer.converter.InvalidInputDataExecption;
+import lcsb.mapviewer.model.map.MiriamData;
+import lcsb.mapviewer.model.map.species.Element;
+
+public abstract class SbmlElementParser<T extends org.sbml.jsbml.Symbol> {
+  Logger logger = Logger.getLogger(SbmlElementParser.class);
+
+  Layout layout;
+
+  public SbmlElementParser(Layout layout) {
+    this.layout = layout;
+  }
+
+  public List<Element> parseList(Model sbmlModel) throws InvalidInputDataExecption {
+    List<Element> result = new ArrayList<>();
+    for (T sbmlElement : getSbmlElementList(sbmlModel)) {
+      result.add(parse(sbmlElement));
+    }
+    if (layout != null) {
+      return mergeLayout(result, layout);
+    } else {
+      return result;
+    }
+  }
+
+  protected abstract ListOf<T> getSbmlElementList(Model sbmlModel);
+
+  private List<Element> mergeLayout(List<Element> elements, Layout sbmlLayout) throws InvalidInputDataExecption {
+    Set<Element> used = new HashSet<>();
+    Map<String, Element> elementById = new HashMap<>();
+    for (Element species : elements) {
+      if (elementById.get(species.getElementId()) != null) {
+        throw new InvalidInputDataExecption("Duplicated element id: " + species.getElementId());
+      }
+      elementById.put(species.getElementId(), species);
+    }
+    List<Element> result = new ArrayList<>();
+
+    for (Pair<String, AbstractReferenceGlyph> idGlyphPair : getGlyphs(sbmlLayout)) {
+      String id = idGlyphPair.getLeft();
+      Element source = elementById.get(id);
+      if (source == null) {
+        throw new InvalidInputDataExecption("Layout contains invalid Species id: " + idGlyphPair.getLeft());
+      }
+      used.add(source);
+      AbstractReferenceGlyph glyph = idGlyphPair.getRight();
+      Element SpeciesWithLayout = source.copy();
+      SpeciesWithLayout.setElementId(glyph.getId());
+      SpeciesWithLayout.setX(glyph.getBoundingBox().getPosition().getX());
+      SpeciesWithLayout.setY(glyph.getBoundingBox().getPosition().getY());
+      SpeciesWithLayout.setWidth(glyph.getBoundingBox().getDimensions().getWidth());
+      SpeciesWithLayout.setHeight(glyph.getBoundingBox().getDimensions().getHeight());
+      result.add(SpeciesWithLayout);
+    }
+    for (Element Species : elements) {
+      if (!used.contains(Species)) {
+        logger.warn("Layout doesn't contain information about Element: " + Species.getElementId());
+        result.add(Species);
+      }
+    }
+    return result;
+  }
+
+  protected abstract List<Pair<String, AbstractReferenceGlyph>> getGlyphs(Layout sbmlLayout);
+
+  protected abstract Element parse(T species) throws InvalidInputDataExecption;
+
+  protected Set<MiriamData> parseAnnotation(Annotation annotation) {
+    if (annotation.getCVTermCount() > 0) {
+      throw new NotImplementedException();
+    }
+    Set<MiriamData> result = new HashSet<>();
+    return result;
+  }
+
+}
diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlParser.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlParser.java
index 357fcfefaf317e53937a7705f6139107c46efda0..7e32722234fe9ed7aaf6598e407dfac2d71d72fa 100644
--- a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlParser.java
+++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlParser.java
@@ -49,12 +49,14 @@ public class SbmlParser implements IConverter {
       Layout layout = getSbmlLayout(sbmlModel);
 
       SbmlCompartmentParser compartmentParser = new SbmlCompartmentParser(layout);
+      SbmlSpeciesParser speciesParser = new SbmlSpeciesParser(layout);
 
       Set<MiriamData> annotations = compartmentParser.parseAnnotation(sbmlModel.getAnnotation());
       if (annotations.size() > 0) {
         throw new NotImplementedException("Annotations not implemented for model");
       }
       model.addElements(compartmentParser.parseList(sbmlModel));
+      model.addElements(speciesParser.parseList(sbmlModel));
       if (sbmlModel.getConstraintCount() > 0) {
         throw new NotImplementedException("Constraints not implemented for model");
       }
@@ -91,9 +93,6 @@ public class SbmlParser implements IConverter {
       if (sbmlModel.getRuleCount() > 0) {
         throw new NotImplementedException("Rule not implemented for model");
       }
-      if (sbmlModel.getSpeciesCount() > 0) {
-        throw new NotImplementedException("Species not implemented for model");
-      }
       if (sbmlModel.getSpeciesReferenceCount() > 0) {
         throw new NotImplementedException("SpeciesReference not implemented for model");
       }
@@ -120,7 +119,7 @@ public class SbmlParser implements IConverter {
       double minX = Double.MAX_VALUE;
       double minY = Double.MAX_VALUE;
       for (Element element : model.getElements()) {
-        if (element.getX() == null) {
+        if (element.getWidth() == 0.0) {
           throw new NotImplementedException("Element without layout not implemented");
         }
         width = Math.max(width, element.getX() + element.getWidth());
@@ -147,7 +146,7 @@ public class SbmlParser implements IConverter {
         if (plugin.getClass().equals(org.sbml.jsbml.ext.layout.LayoutModelPlugin.class)) {
           LayoutModelPlugin layoutPlugin = (LayoutModelPlugin) plugin;
           if (layoutPlugin.getLayoutCount() == 0) {
-            logger.warn("Layout plugin available but not layouts defined");
+            logger.warn("Layout plugin available but no layouts defined");
           } else if (layoutPlugin.getLayoutCount() > 1) {
             logger.warn(layoutPlugin.getLayoutCount() + " layouts defined. Using first one.");
             layout = layoutPlugin.getLayout(0);
diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlSpeciesParser.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlSpeciesParser.java
new file mode 100644
index 0000000000000000000000000000000000000000..e5d5547c4de7caab6e0d8323379a5dfd7fb5ecee
--- /dev/null
+++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlSpeciesParser.java
@@ -0,0 +1,69 @@
+package lcsb.mapviewer.converter.model.sbml;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.stream.XMLStreamException;
+
+import org.apache.log4j.Logger;
+import org.sbml.jsbml.ListOf;
+import org.sbml.jsbml.Model;
+import org.sbml.jsbml.ext.layout.AbstractReferenceGlyph;
+import org.sbml.jsbml.ext.layout.Layout;
+import org.sbml.jsbml.ext.layout.SpeciesGlyph;
+
+import lcsb.mapviewer.common.Pair;
+import lcsb.mapviewer.common.exception.InvalidStateException;
+import lcsb.mapviewer.converter.InvalidInputDataExecption;
+import lcsb.mapviewer.model.map.species.Species;
+import lcsb.mapviewer.model.map.species.Unknown;
+
+public class SbmlSpeciesParser extends SbmlElementParser<org.sbml.jsbml.Species> {
+  Logger logger = Logger.getLogger(SbmlSpeciesParser.class);
+
+  public SbmlSpeciesParser(Layout layout) {
+    super(layout);
+  }
+
+  protected Species parse(org.sbml.jsbml.Species species) throws InvalidInputDataExecption {
+    String type = species.getSpeciesType();
+    Class<? extends Species> clazz = null;
+    if (type == null || type.isEmpty()) {
+      clazz = Unknown.class;
+    }
+    if (clazz == null) {
+      throw new InvalidInputDataExecption("Unknown species type: " + type);
+    }
+    Species result;
+    try {
+      result = clazz.getConstructor(String.class).newInstance(species.getId());
+      result.setMiriamData(parseAnnotation(species.getAnnotation()));
+      result.setName(species.getName());
+      try {
+        result.setNotes(species.getNotesString());
+      } catch (XMLStreamException e) {
+        throw new InvalidInputDataExecption(species.getId() + " Invalid Species notes", e);
+      }
+      return result;
+    } catch (SecurityException | NoSuchMethodException | InstantiationException | IllegalAccessException
+        | IllegalArgumentException | InvocationTargetException e) {
+      throw new InvalidStateException(e);
+    }
+  }
+
+  @Override
+  protected ListOf<org.sbml.jsbml.Species> getSbmlElementList(Model sbmlModel) {
+    return sbmlModel.getListOfSpecies();
+  }
+
+  @Override
+  protected List<Pair<String, AbstractReferenceGlyph>> getGlyphs(Layout sbmlLayout) {
+    List<Pair<String, AbstractReferenceGlyph>> result = new ArrayList<>();
+    for (SpeciesGlyph glyph : sbmlLayout.getListOfSpeciesGlyphs()) {
+      result.add(new Pair<String, AbstractReferenceGlyph>(glyph.getSpecies(), glyph));
+    }
+    return result;
+  }
+
+}
diff --git a/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/GenericSbmlParserTest.java b/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/GenericSbmlParserTest.java
index 835fe52df8cb3c10948025d3883a51de1c596c3b..d28517873a9e0e59e7528df3e46041049e2161fa 100644
--- a/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/GenericSbmlParserTest.java
+++ b/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/GenericSbmlParserTest.java
@@ -64,8 +64,6 @@ public class GenericSbmlParserTest {
       Model model = converter.createModel(new ConverterParams().filename(filePath.toString()));
       model.setName(null);
 
-      Compartment c = new SquareCompartment((Compartment) model.getElements().iterator().next());
-
       // Create and display image of parsed map
       AbstractImageGenerator.Params params = new AbstractImageGenerator.Params().height(model.getHeight())
           .width(model.getWidth()).nested(true).scale(1).level(20).x(0).y(0).model(model);
diff --git a/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/SbmlParserTest.java b/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/SbmlParserTest.java
index b0da6b65b91d7c8aada9ef31d8342aa868c2bf50..72a079086fa04dceed1ee2d1033a3e1b12aed2ec 100644
--- a/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/SbmlParserTest.java
+++ b/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/SbmlParserTest.java
@@ -14,6 +14,7 @@ import lcsb.mapviewer.converter.ConverterParams;
 import lcsb.mapviewer.converter.InvalidInputDataExecption;
 import lcsb.mapviewer.model.map.compartment.Compartment;
 import lcsb.mapviewer.model.map.model.Model;
+import lcsb.mapviewer.model.map.species.Species;
 
 public class SbmlParserTest {
   Logger logger = Logger.getLogger(SbmlParserTest.class);
@@ -37,4 +38,23 @@ public class SbmlParserTest {
     assertFalse(compartment.getClass().equals(Compartment.class));
   }
 
+  @Test
+  public void testParseSpecies() throws FileNotFoundException, InvalidInputDataExecption {
+    Model model = parser.createModel(
+        new ConverterParams().filename("testFiles/layoutExample/SpeciesGlyph_Example_level2_level3.xml"));
+    assertNotNull(model);
+    assertEquals(1, model.getElements().size());
+    Species glucoseSpecies = model.getElementByElementId("SpeciesGlyph_Glucose");
+    assertNotNull(glucoseSpecies.getX());
+    assertNotNull(glucoseSpecies.getY());
+    assertTrue(glucoseSpecies.getWidth()>0);
+    assertTrue(glucoseSpecies.getHeight()>0);
+    assertNotNull(model.getHeight());
+    assertNotNull(model.getWidth());
+    assertTrue(model.getWidth() >= glucoseSpecies.getX() + glucoseSpecies.getWidth());
+    assertTrue(model.getHeight() >= glucoseSpecies.getY() + glucoseSpecies.getHeight());
+    assertFalse(glucoseSpecies.getClass().equals(Species.class));
+  }
+
+  
 }