From 836994f33cf56b82fdae8a0623ecb8adeb17693e Mon Sep 17 00:00:00 2001
From: Piotr Gawron <piotr.gawron@uni.lu>
Date: Thu, 21 Dec 2017 16:16:38 +0100
Subject: [PATCH] export of sbml reaction without layout

---
 .../model/sbml/SbmlBioEntityExporter.java     | 84 +++++++++++++++++++
 .../model/sbml/SbmlElementExporter.java       | 71 +---------------
 .../model/sbml/SbmlElementParser.java         | 20 +++--
 .../converter/model/sbml/SbmlExporter.java    |  2 +
 .../converter/model/sbml/SbmlParser.java      |  2 +-
 .../model/sbml/SbmlReactionExporter.java      | 63 ++++++++++++++
 .../model/sbml/SbmlReactionParser.java        | 12 ++-
 .../model/sbml/SbmlSpeciesParser.java         |  2 +-
 .../model/sbml/SbmlExporterTest.java          | 17 +---
 .../layout/ApplySimpleLayoutModelCommand.java |  2 -
 .../lcsb/mapviewer/model/map/BioEntity.java   |  2 +
 .../model/map/reaction/Reaction.java          |  5 ++
 12 files changed, 187 insertions(+), 95 deletions(-)
 create mode 100644 converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlBioEntityExporter.java
 create mode 100644 converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlReactionExporter.java

diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlBioEntityExporter.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlBioEntityExporter.java
new file mode 100644
index 0000000000..1a18c6ef25
--- /dev/null
+++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlBioEntityExporter.java
@@ -0,0 +1,84 @@
+package lcsb.mapviewer.converter.model.sbml;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.xml.stream.XMLStreamException;
+
+import org.apache.log4j.Logger;
+import org.sbml.jsbml.Model;
+import org.sbml.jsbml.ext.layout.AbstractReferenceGlyph;
+import org.sbml.jsbml.ext.layout.Layout;
+
+import lcsb.mapviewer.common.exception.InvalidStateException;
+import lcsb.mapviewer.model.map.BioEntity;
+import lcsb.mapviewer.model.map.InconsistentModelException;
+
+public abstract class SbmlBioEntityExporter<T extends BioEntity, S extends org.sbml.jsbml.AbstractNamedSBase> {
+  Logger logger = Logger.getLogger(SbmlBioEntityExporter.class);
+
+  Layout layout;
+
+  lcsb.mapviewer.model.map.model.Model minervaModel;
+  Model sbmlModel;
+
+  Map<String, S> sbmlElementByElementId = new HashMap<>();
+  Map<String, AbstractReferenceGlyph> sbmlGlyphByElementId = new HashMap<>();
+
+  private Map<String, S> sbmlElementByElementNameAndCompartmentName = new HashMap<>();
+
+  public SbmlBioEntityExporter(Layout sbmlLayout, lcsb.mapviewer.model.map.model.Model minervaModel) {
+    this.layout = sbmlLayout;
+    this.minervaModel = minervaModel;
+  }
+
+  public void exportElements(Model model) throws InconsistentModelException {
+    sbmlModel = model;
+    Collection<T> speciesList = getElementList();
+    for (T species : speciesList) {
+      S sbmlCompartment = getSbmlElement(species, null);
+
+      if (sbmlElementByElementId.get(species.getElementId()) != null) {
+        throw new InconsistentModelException("More than one species with id: " + species.getElementId());
+      }
+      sbmlElementByElementId.put(species.getElementId(), sbmlCompartment);
+    }
+    for (T species : speciesList) {
+      AbstractReferenceGlyph compartmentGlyph = createGlyph(species);
+      sbmlGlyphByElementId.put(species.getElementId(), compartmentGlyph);
+    }
+  }
+
+  protected abstract Collection<T> getElementList();
+
+  public abstract S createSbmlElement(T element) throws InconsistentModelException;
+
+  protected S getSbmlElement(T element, String compartmentName) throws InconsistentModelException {
+    String mapKey = element.getName() + "\n" + compartmentName;
+    if (sbmlElementByElementNameAndCompartmentName.get(mapKey) == null) {
+      S sbmlElement = createSbmlElement(element);
+      sbmlElement.setName(element.getName());
+      try {
+        sbmlElement.setNotes(element.getNotes());
+      } catch (XMLStreamException e) {
+        throw new InvalidStateException(e);
+      }
+      sbmlElementByElementNameAndCompartmentName.put(mapKey, sbmlElement);
+    }
+    return sbmlElementByElementNameAndCompartmentName.get(mapKey);
+  }
+
+  protected abstract void assignLayoutToGlyph(T element, AbstractReferenceGlyph compartmentGlyph);
+
+  protected AbstractReferenceGlyph createGlyph(T element) {
+    String sbmlCompartmentId = sbmlElementByElementId.get(element.getElementId()).getId();
+    String glyphId = element.getElementId();
+    AbstractReferenceGlyph compartmentGlyph = createElementGlyph(sbmlCompartmentId, glyphId);
+    assignLayoutToGlyph(element, compartmentGlyph);
+    return compartmentGlyph;
+  }
+
+  protected abstract AbstractReferenceGlyph createElementGlyph(String sbmlCompartmentId, String glyphId);
+
+}
diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlElementExporter.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlElementExporter.java
index de56245f1f..d0aebc087f 100644
--- a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlElementExporter.java
+++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlElementExporter.java
@@ -1,75 +1,20 @@
 package lcsb.mapviewer.converter.model.sbml;
 
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.xml.stream.XMLStreamException;
-
 import org.apache.log4j.Logger;
-import org.sbml.jsbml.Model;
 import org.sbml.jsbml.ext.layout.AbstractReferenceGlyph;
 import org.sbml.jsbml.ext.layout.BoundingBox;
 import org.sbml.jsbml.ext.layout.Dimensions;
 import org.sbml.jsbml.ext.layout.Layout;
 import org.sbml.jsbml.ext.layout.Point;
 
-import lcsb.mapviewer.common.exception.InvalidStateException;
-import lcsb.mapviewer.model.map.InconsistentModelException;
 import lcsb.mapviewer.model.map.species.Element;
 
-public abstract class SbmlElementExporter<T extends Element, S extends org.sbml.jsbml.Symbol> {
+public abstract class SbmlElementExporter<T extends Element, S extends org.sbml.jsbml.Symbol>
+    extends SbmlBioEntityExporter<T, S> {
   Logger logger = Logger.getLogger(SbmlElementExporter.class);
 
-  Layout layout;
-
-  lcsb.mapviewer.model.map.model.Model minervaModel;
-  Model sbmlModel;
-
-  Map<String, S> sbmlElementByElementId = new HashMap<>();
-  Map<String, AbstractReferenceGlyph> sbmlGlyphByElementId = new HashMap<>();
-
-  private Map<String, S> sbmlElementByElementNameAndCompartmentName = new HashMap<>();
-
   public SbmlElementExporter(Layout sbmlLayout, lcsb.mapviewer.model.map.model.Model minervaModel) {
-    this.layout = sbmlLayout;
-    this.minervaModel = minervaModel;
-  }
-
-  public void exportElements(Model model) throws InconsistentModelException {
-    sbmlModel = model;
-    List<T> speciesList = getElementList();
-    for (T species : speciesList) {
-      S sbmlCompartment = getSbmlElement(species, null);
-
-      if (sbmlElementByElementId.get(species.getElementId()) != null) {
-        throw new InconsistentModelException("More than one species with id: " + species.getElementId());
-      }
-      sbmlElementByElementId.put(species.getElementId(), sbmlCompartment);
-    }
-    for (T species : speciesList) {
-      AbstractReferenceGlyph compartmentGlyph = createCompartmentGlyph(species);
-      sbmlGlyphByElementId.put(species.getElementId(), compartmentGlyph);
-    }
-  }
-
-  protected abstract List<T> getElementList();
-
-  public abstract S createSbmlElement(T element) throws InconsistentModelException;
-
-  protected S getSbmlElement(T element, String compartmentName) throws InconsistentModelException {
-    String mapKey = element.getName() + "\n" + compartmentName;
-    if (sbmlElementByElementNameAndCompartmentName.get(mapKey) == null) {
-      S sbmlElement = createSbmlElement(element);
-      sbmlElement.setName(element.getName());
-      try {
-        sbmlElement.setNotes(element.getNotes());
-      } catch (XMLStreamException e) {
-        throw new InvalidStateException(e);
-      }
-      sbmlElementByElementNameAndCompartmentName.put(mapKey, sbmlElement);
-    }
-    return sbmlElementByElementNameAndCompartmentName.get(mapKey);
+    super(sbmlLayout, minervaModel);
   }
 
   protected void assignLayoutToGlyph(T element, AbstractReferenceGlyph compartmentGlyph) {
@@ -84,14 +29,4 @@ public abstract class SbmlElementExporter<T extends Element, S extends org.sbml.
     compartmentGlyph.setBoundingBox(boundingBox);
   }
 
-  protected AbstractReferenceGlyph createCompartmentGlyph(T compartment) {
-    String sbmlCompartmentId = sbmlElementByElementId.get(compartment.getElementId()).getId();
-    String glyphId = compartment.getElementId();
-    AbstractReferenceGlyph compartmentGlyph = createElementGlyph(sbmlCompartmentId, glyphId);
-    assignLayoutToGlyph(compartment, compartmentGlyph);
-    return compartmentGlyph;
-  }
-
-  protected abstract AbstractReferenceGlyph createElementGlyph(String sbmlCompartmentId, String glyphId);
-
 }
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
index f97d872d5f..5250fc675f 100644
--- 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
@@ -35,28 +35,32 @@ public abstract class SbmlElementParser<T extends org.sbml.jsbml.Symbol> {
   public List<Element> parseList(Model sbmlModel) throws InvalidInputDataExecption {
     List<Element> result = new ArrayList<>();
     for (T sbmlElement : getSbmlElementList(sbmlModel)) {
-      result.add(parse(sbmlElement, sbmlModel));
+      Element element = parse(sbmlElement, sbmlModel);
+      result.add(element);
+      elementBySbmlId.put(element.getElementId(), element);
     }
     return result;
   }
 
   protected abstract ListOf<T> getSbmlElementList(Model sbmlModel);
 
+  Map<String, Element> elementBySbmlId = new HashMap<>();
+
+  public Element getAnyElementBySbmlElementId(String id) {
+    return elementBySbmlId.get(id);
+  }
+
   protected List<Element> mergeLayout(List<? extends Element> elements, Layout sbmlLayout, Model sbmlModel)
       throws InvalidInputDataExecption {
     Set<String> used = new HashSet<>();
-    Map<String, Element> elementById = new HashMap<>();
     List<Element> result = new ArrayList<>();
     for (Element species : elements) {
-      if (elementById.get(species.getElementId()) != null) {
-        throw new InvalidInputDataExecption("Duplicated element id: " + species.getElementId());
-      }
-      elementById.put(species.getElementId(), species);
+      elementBySbmlId.put(species.getElementId(), species);
     }
 
     for (Pair<String, AbstractReferenceGlyph> idGlyphPair : getGlyphs(sbmlLayout)) {
       String id = idGlyphPair.getLeft();
-      Element source = elementById.get(id);
+      Element source = elementBySbmlId.get(id);
       if (source == null) {
         throw new InvalidInputDataExecption("Layout contains invalid Species id: " + idGlyphPair.getLeft());
       }
@@ -70,6 +74,8 @@ public abstract class SbmlElementParser<T extends org.sbml.jsbml.Symbol> {
       elementWithLayout.setHeight(glyph.getBoundingBox().getDimensions().getHeight());
       minervaModel.addElement(elementWithLayout);
       result.add(elementWithLayout);
+      elementBySbmlId.put(id, elementWithLayout);
+      elementBySbmlId.put(elementWithLayout.getElementId(), elementWithLayout);
     }
     for (Element element : elements) {
       if (!used.contains(element.getElementId())) {
diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlExporter.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlExporter.java
index 2ce062a880..0a54f2fa59 100644
--- a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlExporter.java
+++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlExporter.java
@@ -22,8 +22,10 @@ public class SbmlExporter {
 
     SbmlCompartmentExporter compartmentExporter = new SbmlCompartmentExporter(layout, model);
     SbmlSpeciesExporter speciesExporter = new SbmlSpeciesExporter(layout, model, compartmentExporter);
+    SbmlReactionExporter reactionExporter = new SbmlReactionExporter(layout, model, speciesExporter);
     compartmentExporter.exportElements(result);
     speciesExporter.exportElements(result);
+    reactionExporter.exportElements(result);
 
     // // Create some sample content in the SBML model.
     // Species specOne = result.createSpecies("test_spec1", compartment);
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 2847e01973..733826af7b 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
@@ -62,7 +62,7 @@ public class SbmlParser implements IConverter {
 
       SbmlCompartmentParser compartmentParser = new SbmlCompartmentParser(layout, model);
       SbmlSpeciesParser speciesParser = new SbmlSpeciesParser(layout, model);
-      SbmlReactionParser reactionParser = new SbmlReactionParser(layout, model);
+      SbmlReactionParser reactionParser = new SbmlReactionParser(layout, model, speciesParser);
 
       Set<MiriamData> annotations = compartmentParser.parseAnnotation(sbmlModel.getAnnotation());
       if (annotations.size() > 0) {
diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlReactionExporter.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlReactionExporter.java
new file mode 100644
index 0000000000..092a3b7679
--- /dev/null
+++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlReactionExporter.java
@@ -0,0 +1,63 @@
+package lcsb.mapviewer.converter.model.sbml;
+
+import java.util.Collection;
+
+import org.apache.log4j.Logger;
+import org.sbml.jsbml.Species;
+import org.sbml.jsbml.ext.layout.AbstractReferenceGlyph;
+import org.sbml.jsbml.ext.layout.Layout;
+
+import lcsb.mapviewer.model.map.InconsistentModelException;
+import lcsb.mapviewer.model.map.reaction.Modifier;
+import lcsb.mapviewer.model.map.reaction.Product;
+import lcsb.mapviewer.model.map.reaction.Reactant;
+import lcsb.mapviewer.model.map.reaction.Reaction;
+
+public class SbmlReactionExporter extends SbmlBioEntityExporter<Reaction, org.sbml.jsbml.Reaction> {
+  Logger logger = Logger.getLogger(SbmlReactionExporter.class);
+  private int idCounter = 0;
+  private SbmlSpeciesExporter speciesExporter;
+
+  public SbmlReactionExporter(Layout layout, lcsb.mapviewer.model.map.model.Model minervaModel,
+      SbmlSpeciesExporter speciesExporter) {
+    super(layout, minervaModel);
+    this.speciesExporter = speciesExporter;
+  }
+
+  @Override
+  public org.sbml.jsbml.Reaction createSbmlElement(Reaction reaction) throws InconsistentModelException {
+    org.sbml.jsbml.Reaction result = sbmlModel.createReaction("reaction_" + (idCounter++));
+    for (Product product : reaction.getProducts()) {
+      Species sbmlSymbol = speciesExporter.sbmlElementByElementId.get(product.getElement().getElementId());
+      result.createProduct(sbmlSymbol);
+    }
+    for (Reactant reactant : reaction.getReactants()) {
+      Species sbmlSymbol = speciesExporter.sbmlElementByElementId.get(reactant.getElement().getElementId());
+      result.createReactant(sbmlSymbol);
+    }
+    for (Modifier modifier : reaction.getModifiers()) {
+      Species sbmlSymbol = speciesExporter.sbmlElementByElementId.get(modifier.getElement().getElementId());
+      result.createModifier(sbmlSymbol);
+    }
+    return result;
+  }
+
+  @Override
+  protected AbstractReferenceGlyph createElementGlyph(String sbmlElementId, String glyphId) {
+//    AbstractReferenceGlyph speciesGlyph = layout.createReactionGlyph(glyphId, sbmlElementId);
+//    return speciesGlyph;
+    return null;
+  }
+
+  @Override
+  protected Collection<Reaction> getElementList() {
+    return minervaModel.getReactions();
+  }
+
+  @Override
+  protected void assignLayoutToGlyph(Reaction element, AbstractReferenceGlyph compartmentGlyph) {
+    // TODO Auto-generated method stub
+
+  }
+
+}
diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlReactionParser.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlReactionParser.java
index f96d4e2f7b..33b08697c0 100644
--- a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlReactionParser.java
+++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlReactionParser.java
@@ -55,9 +55,13 @@ public class SbmlReactionParser {
   lcsb.mapviewer.model.map.model.Model minervaModel;
   ElementUtils eu = new ElementUtils();
 
-  public SbmlReactionParser(Layout sbmlLayout, lcsb.mapviewer.model.map.model.Model minervaModel) {
+  SbmlSpeciesParser speciesParser;
+
+  public SbmlReactionParser(Layout sbmlLayout, lcsb.mapviewer.model.map.model.Model minervaModel,
+      SbmlSpeciesParser speciesParser) {
     this.layout = sbmlLayout;
     this.minervaModel = minervaModel;
+    this.speciesParser = speciesParser;
   }
 
   public List<Reaction> parseList(Model sbmlModel) throws InvalidInputDataExecption {
@@ -224,7 +228,11 @@ public class SbmlReactionParser {
     Set<Reaction> elementsToRemove = new HashSet<>();
     for (Reaction reaction : reactions) {
       if (!used.contains(reaction)) {
-        logger.warn("Layout doesn't contain information about Reaction: " + reaction.getIdReaction());
+        for (ReactionNode node : reaction.getReactionNodes()) {
+          // we might have different elements here, the reason is that single SBML species
+          // can be split into two or more (due to layout)
+          node.setElement(speciesParser.getAnyElementBySbmlElementId(node.getElement().getElementId()));
+        }
       } else {
         elementsToRemove.add(reaction);
       }
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
index 648d7002ba..7b0900458d 100644
--- 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
@@ -91,7 +91,7 @@ public class SbmlSpeciesParser extends SbmlElementParser<org.sbml.jsbml.Species>
           compartment = compartment2;
         }
       }
-
+      
     }
     if (compartment != null) {
       compartment.addElement(element);
diff --git a/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/SbmlExporterTest.java b/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/SbmlExporterTest.java
index a5a7554748..a6cda5f298 100644
--- a/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/SbmlExporterTest.java
+++ b/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/SbmlExporterTest.java
@@ -21,6 +21,7 @@ import lcsb.mapviewer.model.map.compartment.Compartment;
 import lcsb.mapviewer.model.map.model.Model;
 import lcsb.mapviewer.model.map.reaction.Reaction;
 import lcsb.mapviewer.model.map.reaction.ReactionNode;
+import lcsb.mapviewer.model.map.species.Element;
 import lcsb.mapviewer.model.map.species.Species;
 
 public class SbmlExporterTest {
@@ -51,7 +52,8 @@ public class SbmlExporterTest {
     String xml = exporter.toXml(originalModel);
     ByteArrayInputStream stream = new ByteArrayInputStream(xml.getBytes("UTF-8"));
     Model result = parser.createModel(new ConverterParams().inputStream(stream));
-
+//    showImage(originalModel);
+//    showImage(result);
     return result;
   }
 
@@ -118,17 +120,4 @@ public class SbmlExporterTest {
     assertEquals(2, reaction.getOperators().size());
   }
 
-  @Test
-  public void testReactionWithoutLayout() throws Exception {
-    Model model = getModelAfterSerializing("testFiles/layoutExample/Complete_Example_level2.xml");
-    assertNotNull(model);
-    assertEquals(1, model.getReactions().size());
-    Reaction reaction = model.getReactions().iterator().next();
-    for (ReactionNode node : reaction.getReactionNodes()) {
-      assertNotNull(node.getLine());
-      assertTrue(node.getLine().length() > 0);
-    }
-    assertEquals(2, reaction.getOperators().size());
-  }
-
 }
diff --git a/model-command/src/main/java/lcsb/mapviewer/commands/layout/ApplySimpleLayoutModelCommand.java b/model-command/src/main/java/lcsb/mapviewer/commands/layout/ApplySimpleLayoutModelCommand.java
index 83cfd8e86b..041820ea04 100644
--- a/model-command/src/main/java/lcsb/mapviewer/commands/layout/ApplySimpleLayoutModelCommand.java
+++ b/model-command/src/main/java/lcsb/mapviewer/commands/layout/ApplySimpleLayoutModelCommand.java
@@ -114,8 +114,6 @@ public class ApplySimpleLayoutModelCommand extends ApplyLayoutModelCommand {
 
   protected void modifyElementLocation(Collection<Element> elements, Compartment parent, Point2D minPoint,
       Dimension2D dimension) {
-    logger.debug(minPoint);
-    logger.debug(dimension);
     Set<Compartment> compartments = new HashSet<>();
     Set<Species> elementToAlign = new HashSet<>();
     Map<Compartment, Set<Element>> elementsByStaticCompartment = new HashMap<>();
diff --git a/model/src/main/java/lcsb/mapviewer/model/map/BioEntity.java b/model/src/main/java/lcsb/mapviewer/model/map/BioEntity.java
index 70319d5914..068af61908 100644
--- a/model/src/main/java/lcsb/mapviewer/model/map/BioEntity.java
+++ b/model/src/main/java/lcsb/mapviewer/model/map/BioEntity.java
@@ -173,4 +173,6 @@ public interface BioEntity extends Serializable {
    */
   Model getModel();
 
+  String getElementId();
+
 }
diff --git a/model/src/main/java/lcsb/mapviewer/model/map/reaction/Reaction.java b/model/src/main/java/lcsb/mapviewer/model/map/reaction/Reaction.java
index 5d04e7781c..d1139cf5a6 100644
--- a/model/src/main/java/lcsb/mapviewer/model/map/reaction/Reaction.java
+++ b/model/src/main/java/lcsb/mapviewer/model/map/reaction/Reaction.java
@@ -621,6 +621,11 @@ public class Reaction implements BioEntity {
     return idReaction;
   }
 
+  @Override
+  public String getElementId() {
+    return getIdReaction();
+  }
+
   /**
    * @param idReaction
    *          the idReaction to set
-- 
GitLab