From cd8676d94aeaede447bc5d55ea55a52fe54689a5 Mon Sep 17 00:00:00 2001
From: Piotr Gawron <p.gawron@atcomp.pl>
Date: Wed, 19 Mar 2025 08:53:56 +0100
Subject: [PATCH] export to sbgn could generate notes without schema

---
 CHANGELOG                                     |  1 +
 .../model/sbgnml/SbgnmlXmlConverter.java      | 73 ++++++++-----------
 .../model/sbgnml/SbgnmlXmlExporter.java       |  2 +-
 .../lcsb/mapviewer/converter/Converter.java   | 48 ++++++------
 4 files changed, 52 insertions(+), 72 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index 619737659d..92f2c18966 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -23,6 +23,7 @@ minerva (19.0.0~alpha.0) stable; urgency=medium
   * Bug fix: when removing project the layer texts/rectangles/ovals were not
     removed
   * Bug fix: index.html has been cached but should not (#2210)
+  * Bug fix: export to SBGN-ML could generate invalid notes node for the file
 
  -- Piotr Gawron <piotr.gawron@uni.lu>  Wed, 18 Sep 2024 13:00:00 +0200
 
diff --git a/converter-SBGNML/src/main/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlXmlConverter.java b/converter-SBGNML/src/main/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlXmlConverter.java
index 7d132fdae4..20445f8986 100644
--- a/converter-SBGNML/src/main/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlXmlConverter.java
+++ b/converter-SBGNML/src/main/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlXmlConverter.java
@@ -1,11 +1,19 @@
 package lcsb.mapviewer.converter.model.sbgnml;
 
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.StringWriter;
-import java.util.Arrays;
-import java.util.List;
+import lcsb.mapviewer.common.MimeType;
+import lcsb.mapviewer.common.MinervaLoggerAppender;
+import lcsb.mapviewer.converter.Converter;
+import lcsb.mapviewer.converter.ConverterException;
+import lcsb.mapviewer.converter.ConverterParams;
+import lcsb.mapviewer.converter.InvalidInputDataExecption;
+import lcsb.mapviewer.converter.model.sbgnml.parser.NotesConverter;
+import lcsb.mapviewer.model.map.model.Model;
+import lcsb.mapviewer.modelutils.map.LogFormatter;
+import org.apache.commons.io.output.ByteArrayOutputStream;
+import org.sbgn.SbgnUtil;
+import org.sbgn.bindings.Sbgn;
+import org.springframework.stereotype.Component;
+import org.w3c.dom.Document;
 
 import javax.xml.XMLConstants;
 import javax.xml.parsers.DocumentBuilderFactory;
@@ -18,30 +26,17 @@ import javax.xml.transform.TransformerFactory;
 import javax.xml.transform.dom.DOMSource;
 import javax.xml.transform.stream.StreamResult;
 import javax.xml.transform.stream.StreamSource;
-
-import org.apache.commons.io.output.ByteArrayOutputStream;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.sbgn.SbgnUtil;
-import org.sbgn.bindings.Sbgn;
-import org.springframework.stereotype.Component;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-
-import lcsb.mapviewer.common.MimeType;
-import lcsb.mapviewer.common.MinervaLoggerAppender;
-import lcsb.mapviewer.converter.Converter;
-import lcsb.mapviewer.converter.ConverterException;
-import lcsb.mapviewer.converter.ConverterParams;
-import lcsb.mapviewer.converter.InvalidInputDataExecption;
-import lcsb.mapviewer.model.map.model.Model;
-import lcsb.mapviewer.modelutils.map.LogFormatter;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringWriter;
+import java.util.Collections;
+import java.util.List;
 
 @Component
 public class SbgnmlXmlConverter extends Converter {
 
-  @SuppressWarnings("unused")
-  private static Logger logger = LogManager.getLogger();
+  private final NotesConverter notesConverter = new NotesConverter();
 
   @Override
   public Model createModel(final ConverterParams params) throws InvalidInputDataExecption, ConverterException {
@@ -72,13 +67,13 @@ public class SbgnmlXmlConverter extends Converter {
       Templates template = factory
           .newTemplates(new StreamSource(classLoader.getResourceAsStream("rename_id_list_attribute.xsl")));
 
-      Transformer xformer = template.newTransformer();
+      Transformer transformer = template.newTransformer();
 
       ByteArrayOutputStream output = new ByteArrayOutputStream();
       Source source = new StreamSource(inputStream);
       Result result = new StreamResult(output);
 
-      xformer.transform(source, result);
+      transformer.transform(source, result);
       return inputStream2File(output.toInputStream());
 
     } catch (final Exception e) {
@@ -96,13 +91,14 @@ public class SbgnmlXmlConverter extends Converter {
       exportedData = exporter.toSbgnml(model);
       if (!appender.getWarnings().isEmpty()) {
         for (final String entry : new LogFormatter().createFormattedWarnings(appender.getWarnings())) {
-          notes.append("\n" + entry);
+          notes.append("\n").append(entry);
         }
       }
     } finally {
       MinervaLoggerAppender.unregisterLogEventStorage(appender);
     }
     try {
+      exportedData.setNotes(notesConverter.createNotesNode(notes.toString()));
       ByteArrayOutputStream baos = new ByteArrayOutputStream();
       SbgnUtil.writeTo(exportedData, baos);
 
@@ -113,23 +109,12 @@ public class SbgnmlXmlConverter extends Converter {
           .newDocumentBuilder()
           .parse(baos.toInputStream());
 
-      if (notes.length() > 0) {
-        Element bodyNode = input.createElement("body");
-        bodyNode.setAttribute("xmlns", "http://www.w3.org/1999/xhtml");
-        bodyNode.setTextContent(notes.toString());
-
-        Element notesNode = input.createElement("notes");
-        notesNode.appendChild(bodyNode);
-
-        input.getFirstChild().insertBefore(notesNode, input.getFirstChild().getFirstChild());
-      }
-
       TransformerFactory transformerFactory = TransformerFactory.newInstance();
       transformerFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
-      Transformer xformer = transformerFactory.newTransformer();
-      xformer.setOutputProperty(OutputKeys.INDENT, "yes");
+      Transformer transformer = transformerFactory.newTransformer();
+      transformer.setOutputProperty(OutputKeys.INDENT, "yes");
       StringWriter output = new StringWriter();
-      xformer.transform(new DOMSource(input), new StreamResult(output));
+      transformer.transform(new DOMSource(input), new StreamResult(output));
 
       return output.toString();
     } catch (final Exception e) {
@@ -149,7 +134,7 @@ public class SbgnmlXmlConverter extends Converter {
 
   @Override
   public List<String> getFileExtensions() {
-    return Arrays.asList("sbgn");
+    return Collections.singletonList("sbgn");
   }
 
 }
diff --git a/converter-SBGNML/src/main/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlXmlExporter.java b/converter-SBGNML/src/main/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlXmlExporter.java
index 8584db5f3c..4bd341bd11 100644
--- a/converter-SBGNML/src/main/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlXmlExporter.java
+++ b/converter-SBGNML/src/main/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlXmlExporter.java
@@ -178,7 +178,7 @@ public class SbgnmlXmlExporter {
    * Transforms model into SBGN-ML xml.
    *
    * @param model model that should be transformed
-   * @return SBGM-ML xml string for the model
+   * @return SBGN-ML xml string for the model
    */
   public Sbgn toSbgnml(final Model model) throws ConverterException {
     // Reset global variables
diff --git a/converter/src/main/java/lcsb/mapviewer/converter/Converter.java b/converter/src/main/java/lcsb/mapviewer/converter/Converter.java
index b7a3575529..a3a40b1fdf 100644
--- a/converter/src/main/java/lcsb/mapviewer/converter/Converter.java
+++ b/converter/src/main/java/lcsb/mapviewer/converter/Converter.java
@@ -1,5 +1,12 @@
 package lcsb.mapviewer.converter;
 
+import lcsb.mapviewer.common.MimeType;
+import lcsb.mapviewer.model.map.InconsistentModelException;
+import lcsb.mapviewer.model.map.model.Model;
+import org.apache.commons.io.FileUtils;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
 import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.IOException;
@@ -9,29 +16,22 @@ import java.nio.charset.StandardCharsets;
 import java.util.List;
 import java.util.UUID;
 
-import org.apache.commons.io.FileUtils;
-
-import lcsb.mapviewer.common.MimeType;
-import lcsb.mapviewer.model.map.InconsistentModelException;
-import lcsb.mapviewer.model.map.model.Model;
-
 /**
  * Interface used for reading data from file and putting it into {@link Model}
  * object.
- * 
+ *
  * @author Piotr Gawron
- * 
  */
 public abstract class Converter {
 
+  protected static final Logger logger = LogManager.getLogger();
+
   /**
    * Parse input source and transforms it into a model object.
-   * 
-   * @param params
-   *          input params used for reading data
+   *
+   * @param params input params used for reading data
    * @return model obtained from input source
-   * @throws InvalidInputDataExecption
-   *           thrown when input parameters are invalid
+   * @throws InvalidInputDataExecption thrown when input parameters are invalid
    */
   public abstract Model createModel(final ConverterParams params) throws InvalidInputDataExecption, ConverterException;
 
@@ -39,8 +39,7 @@ public abstract class Converter {
    * Generate String representation of the model. Traditionally often XML but can
    * be any other format as well.
    *
-   * @param model
-   *          The MINERVA ${@link Model} to be serialized
+   * @param model The MINERVA ${@link Model} to be serialized
    * @return The translated Model
    */
   public abstract String model2String(final Model model) throws InconsistentModelException, ConverterException;
@@ -68,12 +67,10 @@ public abstract class Converter {
 
   /**
    * Export model to {@link InputStream}.
-   * 
-   * @param model
-   *          model to be exported
+   *
+   * @param model model to be exported
    * @return {@link InputStream} with exported data
-   * @throws InconsistentModelException
-   *           thrown when given model is inconsistent and unable to be exported
+   * @throws InconsistentModelException thrown when given model is inconsistent and unable to be exported
    */
   public InputStream model2InputStream(final Model model)
       throws InconsistentModelException, ConverterException {
@@ -83,14 +80,11 @@ public abstract class Converter {
 
   /**
    * Export model to {@link File}.
-   * 
-   * @param model
-   *          model to be exported
-   * @param filePath
-   *          exported file path
+   *
+   * @param model    model to be exported
+   * @param filePath exported file path
    * @return {@link File} with exported data
-   * @throws InconsistentModelException
-   *           thrown when given model is inconsistent and unable to be exported
+   * @throws InconsistentModelException thrown when given model is inconsistent and unable to be exported
    */
   public File model2File(final Model model, final String filePath)
       throws InconsistentModelException, IOException, ConverterException {
-- 
GitLab