diff --git a/.aspell-api-exceptions.pws b/.aspell-api-exceptions.pws index efa354665f5f6c8bc53784d8acf9e6b591a02141..8589d9cecd52eebe140cd1b92130ef8ba2669f65 100644 --- a/.aspell-api-exceptions.pws +++ b/.aspell-api-exceptions.pws @@ -116,6 +116,7 @@ coeruleus commentId commonName compartmentId +compartmentOrder complexId compulyeast connectedToLdap diff --git a/CHANGELOG b/CHANGELOG index f27a7bc28207ddf045d46d604301709bb912c1cf..987325ebd9551cf3e48918e885a10a027902f73b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,10 +1,17 @@ -minerva (18.0.8) stable; urgency=medium +minerva (18.1.0) stable; urgency=medium + * Small improvement: SBGN-ML import/export is processing notes (#2192) + * Small improvement: SBGN-ML import/export is processing compartmentOrder + (#2193) + * Small improvement: support for links that should be opened immediately + (#2189) * Bug fix: don't create duplicated refresh jobs (#2165) * Bug fix: performance issues with caching suggested query list for chemicals (#2168) * Bug fix: information about species pathway/compartment has not been separated. This caused to export the model into incorrect SBML - species are separated using compartment (#2169) + * Bug fix: exporting model should provide deterministic output for species and + compartments (#2187) -- Piotr Gawron <piotr.gawron@uni.lu> Thu, 19 Dec 2024 13:00:00 +0200 diff --git a/CellDesigner-plugin/pom.xml b/CellDesigner-plugin/pom.xml index 6001e2e64aaad4a6d8e1f7932556ba447f4d56cb..f196ae52a36c970a3631fb0002fc2b31edfdb5ed 100644 --- a/CellDesigner-plugin/pom.xml +++ b/CellDesigner-plugin/pom.xml @@ -5,7 +5,7 @@ <parent> <groupId>lcsb.mapviewer</groupId> <artifactId>parent</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </parent> <artifactId>CellDesigner-plugin</artifactId> <!-- dependency from the MapViewer model --> @@ -50,19 +50,19 @@ <dependency> <groupId>lcsb.mapviewer</groupId> <artifactId>model</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </dependency> <dependency> <groupId>lcsb.mapviewer</groupId> <artifactId>commons</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </dependency> <dependency> <groupId>lcsb.mapviewer</groupId> <artifactId>converter-CellDesigner</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </dependency> <dependency> diff --git a/annotation/pom.xml b/annotation/pom.xml index 6d781a5ea28a476db2e05f951c16418793fc96c8..4f120e85c46f44f56dacae1e61f22a2a7d040615 100644 --- a/annotation/pom.xml +++ b/annotation/pom.xml @@ -5,7 +5,7 @@ <parent> <groupId>lcsb.mapviewer</groupId> <artifactId>parent</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </parent> <artifactId>annotation</artifactId> <name>Annotation module</name> @@ -19,7 +19,7 @@ <dependency> <groupId>lcsb.mapviewer</groupId> <artifactId>model</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </dependency> <!-- dependency from the MapViewer dao --> @@ -27,7 +27,7 @@ <dependency> <groupId>lcsb.mapviewer</groupId> <artifactId>persist</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </dependency> <!-- dependency from the MapViewer cell designer parser (we need access @@ -35,13 +35,13 @@ <dependency> <groupId>lcsb.mapviewer</groupId> <artifactId>converter-CellDesigner</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </dependency> <dependency> <groupId>lcsb.mapviewer</groupId> <artifactId>converter</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </dependency> <!-- Log4J2 --> diff --git a/commons/pom.xml b/commons/pom.xml index 07b9b977cb78b46b3e9d8e16b1c1601f98781d41..4fc21cf7cf6d475e8356d5f772c698eb8827f86b 100644 --- a/commons/pom.xml +++ b/commons/pom.xml @@ -5,7 +5,7 @@ <parent> <groupId>lcsb.mapviewer</groupId> <artifactId>parent</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </parent> <artifactId>commons</artifactId> <name>Mapviewer commons</name> diff --git a/converter-CellDesigner/pom.xml b/converter-CellDesigner/pom.xml index 86b9f56d15043eae1a3e04c7d3aab7e40bb42ed6..7d84518701bdae3e7a0dcde533b7cc70bfe100a2 100644 --- a/converter-CellDesigner/pom.xml +++ b/converter-CellDesigner/pom.xml @@ -5,7 +5,7 @@ <parent> <groupId>lcsb.mapviewer</groupId> <artifactId>parent</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </parent> <artifactId>converter-CellDesigner</artifactId> <name>CellDesigner converter</name> @@ -17,13 +17,13 @@ <dependency> <groupId>lcsb.mapviewer</groupId> <artifactId>model</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </dependency> <dependency> <groupId>lcsb.mapviewer</groupId> <artifactId>converter</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </dependency> <!-- Log4J2 --> diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/CellDesignerXmlParser.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/CellDesignerXmlParser.java index dff6f97af0094312578fb5c09a6d4bf02c6a7b62..d0bceeb60ee61462bcc2f7d95e989360a4834256 100644 --- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/CellDesignerXmlParser.java +++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/CellDesignerXmlParser.java @@ -715,7 +715,7 @@ public class CellDesignerXmlParser extends Converter { final List<Gene> genes = new ArrayList<>(); final List<Rna> rnas = new ArrayList<>(); final List<AntisenseRna> antisenseRnas = new ArrayList<>(); - for (final Element element : model.getElements()) { + for (final Element element : model.getSortedElements()) { if (element instanceof Protein) { proteins.add((Protein) element); } else if (element instanceof Gene) { diff --git a/converter-SBGNML/pom.xml b/converter-SBGNML/pom.xml index ab9af58bd45ec28cb539468291298145177867f4..1d56b0ac8303c7f32a48e0b3689fdc27434c65dc 100644 --- a/converter-SBGNML/pom.xml +++ b/converter-SBGNML/pom.xml @@ -5,7 +5,7 @@ <parent> <groupId>lcsb.mapviewer</groupId> <artifactId>parent</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </parent> <artifactId>converter-SBGNML</artifactId> @@ -20,26 +20,26 @@ <dependency> <groupId>lcsb.mapviewer</groupId> <artifactId>model</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </dependency> <dependency> <groupId>lcsb.mapviewer</groupId> <artifactId>persist</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> <scope>test</scope> </dependency> <dependency> <groupId>lcsb.mapviewer</groupId> <artifactId>converter-CellDesigner</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </dependency> <dependency> <groupId>lcsb.mapviewer</groupId> <artifactId>converter-graphics</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </dependency> <dependency> 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 321f5d8a44ac4e06591d0722efaae71b4fec1682..151f2ced9724130804a01b5767ca3e8d29f3075f 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 @@ -6,7 +6,7 @@ import lcsb.mapviewer.common.geometry.ColorParser; import lcsb.mapviewer.converter.ConverterException; import lcsb.mapviewer.converter.annotation.XmlAnnotationParser; import lcsb.mapviewer.converter.graphics.bioentity.reaction.ReactionConverter; -import lcsb.mapviewer.converter.model.celldesigner.CommonXmlParser; +import lcsb.mapviewer.converter.model.sbgnml.parser.NotesConverter; import lcsb.mapviewer.model.LogMarker; import lcsb.mapviewer.model.ProjectLogEntryType; import lcsb.mapviewer.model.graphics.ArrowType; @@ -168,6 +168,8 @@ public class SbgnmlXmlExporter { private final ColorParser colorParser = new ColorParser(); + private final NotesConverter notesConverter = new NotesConverter(); + private final XmlAnnotationParser xap = new XmlAnnotationParser(new ArrayList<>(), true); private final java.util.Map<Element, String> exportElementIds = new HashMap<>(); @@ -211,7 +213,7 @@ public class SbgnmlXmlExporter { final Sbgn sbgnData = new Sbgn(); - for (final Element element : model.getElements()) { + for (final Element element : model.getSortedElements()) { if (element instanceof Species) { if (((Species) element).getComplex() == null) { final Glyph newGlyph = elementToGlyph(element); @@ -253,25 +255,7 @@ public class SbgnmlXmlExporter { throw new ConverterException("Problem with providing render information"); } - try { - final StringBuilder notes = new StringBuilder(); - notes.append("<html xmlns=\"http://www.w3.org/1999/xhtml\"><head><title/></head><body>"); - if (model.getNotes() != null) { - notes.append(new CommonXmlParser().getNotesXmlContent(model.getNotes())); - } - notes.append("</body></html>"); - - final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - dbf.setNamespaceAware(true); - final DocumentBuilder db; - db = dbf.newDocumentBuilder(); - final Document doc = db.parse(new ByteArrayInputStream(notes.toString().getBytes())); - - map.setNotes(new SBGNBase.Notes()); - map.getNotes().getAny().add((org.w3c.dom.Element) (doc.getFirstChild())); - } catch (final Exception e) { - logger.warn("Problem with processing notes"); - } + map.setNotes(notesConverter.createNotesNode(model.getNotes())); sbgnData.getMap().add(map); return sbgnData; @@ -289,6 +273,10 @@ public class SbgnmlXmlExporter { newGlyph.setId(elementId); newGlyph.setClazz(getGlyphClazzFromElement(element).getClazz()); newGlyph.setLabel(getGlyphLabelFromAlias(element)); + newGlyph.setNotes(notesConverter.createNotesNode(element.getNotes())); + if (element.getZ() != null) { + newGlyph.setCompartmentOrder(element.getZ().floatValue()); + } final Bbox bbox = new Bbox(); bbox.setX(element.getX().floatValue()); @@ -449,7 +437,7 @@ public class SbgnmlXmlExporter { glyph.setClazz(GlyphClazz.STATE_VARIABLE.getClazz()); final Glyph.State state = new Glyph.State(); - if (structuralState.getName().indexOf("@") >= 0) { + if (structuralState.getName().contains("@")) { state.setValue(structuralState.getName().substring(0, structuralState.getName().indexOf("@"))); state.setVariable(structuralState.getName().substring(structuralState.getName().indexOf("@") + 1)); } else { @@ -685,14 +673,14 @@ public class SbgnmlXmlExporter { } if (species instanceof TruncatedProtein) { - if (!uoiText.equals("")) { + if (!uoiText.isEmpty()) { uoiText = uoiText.concat("; "); } uoiText = uoiText.concat("ct:truncatedProtein"); } if ((species.getStateLabel() != null) && (species.getStatePrefix() != null)) { - if (!uoiText.equals("")) { + if (!uoiText.isEmpty()) { uoiText = uoiText.concat("; "); } if (!species.getStatePrefix().equals("free input")) { @@ -703,26 +691,26 @@ public class SbgnmlXmlExporter { if (!uoiText.contains("ct:")) { if (species instanceof Rna) { - if (!uoiText.equals("")) { + if (!uoiText.isEmpty()) { uoiText = uoiText.concat("; "); } uoiText = uoiText.concat("ct:RNA"); } if (species instanceof AntisenseRna) { - if (!uoiText.equals("")) { + if (!uoiText.isEmpty()) { uoiText = uoiText.concat("; "); } uoiText = uoiText.concat("ct:antisenseRNA"); } if (species instanceof Gene) { - if (!uoiText.equals("")) { + if (!uoiText.isEmpty()) { uoiText = uoiText.concat("; "); } uoiText = uoiText.concat("ct:gene"); } } - if (!uoiText.equals("")) { + if (!uoiText.isEmpty()) { uoiGlyph = new Glyph(); uoiGlyph.setClazz(GlyphClazz.UNIT_OF_INFORMATION.getClazz()); uoiGlyph.setId(species.getElementId().concat("uoi")); @@ -1031,7 +1019,7 @@ public class SbgnmlXmlExporter { * * @param reaction the reaction to extract arcs from * @param glyphList list of all glyphs in the map; used only for parsing operators - * @return set of all arcs used in the reaction + * @return list of all arcs used in the reaction */ private List<Arc> getArcsFromReaction(final Reaction reaction, final List<Glyph> glyphList) { final List<Arc> arcList = new ArrayList<>(); @@ -1179,13 +1167,13 @@ public class SbgnmlXmlExporter { final DoubleComparator doubleComparator = new DoubleComparator(); for (int i = 1; i < arcPoints.size() - 1; i++) { final Point2D nextPoint = arcPoints.get(i); - if ((doubleComparator.compare(nextPoint.getX(), new Double(start.getX())) == 0) - && (doubleComparator.compare(nextPoint.getY(), new Double(start.getY())) == 0)) { + if ((doubleComparator.compare(nextPoint.getX(), (double) start.getX()) == 0) + && (doubleComparator.compare(nextPoint.getY(), (double) start.getY()) == 0)) { arc.getNext().clear(); continue; } - if ((doubleComparator.compare(nextPoint.getX(), new Double(end.getX())) == 0) - && (doubleComparator.compare(nextPoint.getY(), new Double(end.getY())) == 0)) { + if ((doubleComparator.compare(nextPoint.getX(), (double) end.getX()) == 0) + && (doubleComparator.compare(nextPoint.getY(), (double) end.getY()) == 0)) { break; } final Next next = new Next(); diff --git a/converter-SBGNML/src/main/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlXmlParser.java b/converter-SBGNML/src/main/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlXmlParser.java index fbeac9272faf24244a4e9bd629a81bb6b78beff5..6e5728d44676d05f5b77857e814edb9125603865 100644 --- a/converter-SBGNML/src/main/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlXmlParser.java +++ b/converter-SBGNML/src/main/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlXmlParser.java @@ -1,38 +1,12 @@ package lcsb.mapviewer.converter.model.sbgnml; -import java.io.ByteArrayInputStream; -import java.io.File; -import java.util.ArrayList; -import java.util.List; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; - -import org.apache.commons.io.FilenameUtils; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.sbgn.GlyphClazz; -import org.sbgn.RenderUtil; -import org.sbgn.SbgnUtil; -import org.sbgn.bindings.Arc; -import org.sbgn.bindings.Arc.End; -import org.sbgn.bindings.Arc.Next; -import org.sbgn.bindings.Arc.Start; -import org.sbgn.bindings.Bbox; -import org.sbgn.bindings.Glyph; -import org.sbgn.bindings.Map; -import org.sbgn.bindings.RenderInformation; -import org.sbgn.bindings.Sbgn; -import org.w3c.dom.Document; -import org.w3c.dom.Node; - import lcsb.mapviewer.common.XmlParser; import lcsb.mapviewer.common.exception.InvalidXmlSchemaException; import lcsb.mapviewer.converter.InvalidInputDataExecption; import lcsb.mapviewer.converter.ZIndexPopulator; import lcsb.mapviewer.converter.annotation.XmlAnnotationParser; -import lcsb.mapviewer.converter.model.celldesigner.annotation.RestAnnotationParser; import lcsb.mapviewer.converter.model.sbgnml.parser.ElementParser; +import lcsb.mapviewer.converter.model.sbgnml.parser.NotesConverter; import lcsb.mapviewer.converter.model.sbgnml.parser.ReactionParser; import lcsb.mapviewer.converter.model.sbgnml.parser.RenderParser; import lcsb.mapviewer.converter.model.sbgnml.structures.Process; @@ -48,24 +22,43 @@ import lcsb.mapviewer.model.map.reaction.Reaction; import lcsb.mapviewer.model.map.species.Complex; import lcsb.mapviewer.model.map.species.Element; import lcsb.mapviewer.model.map.species.Species; +import org.apache.commons.io.FilenameUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.sbgn.GlyphClazz; +import org.sbgn.RenderUtil; +import org.sbgn.SbgnUtil; +import org.sbgn.bindings.Arc; +import org.sbgn.bindings.Arc.End; +import org.sbgn.bindings.Arc.Next; +import org.sbgn.bindings.Arc.Start; +import org.sbgn.bindings.Bbox; +import org.sbgn.bindings.Glyph; +import org.sbgn.bindings.Map; +import org.sbgn.bindings.RenderInformation; +import org.sbgn.bindings.Sbgn; +import org.w3c.dom.Node; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; /** * This class is a parser for SBGN-ML files. - * - * @author Michał Kuźma * + * @author Michał Kuźma */ public class SbgnmlXmlParser { /** * Default class logger. */ - private Logger logger = LogManager.getLogger(); + private final Logger logger = LogManager.getLogger(); /** * List of all arcs that should be translated as activity flow reactions. */ - private List<Arc> activityFlowArcs = new ArrayList<>(); + private final List<Arc> activityFlowArcs = new ArrayList<>(); private Model model; @@ -77,17 +70,15 @@ public class SbgnmlXmlParser { private ReactionParser reactionParser; + private final NotesConverter notesConverter = new NotesConverter(); + /** * Method used to create a model from SBGN-ML file. * - * @param filename - * The filename of the input file. - * @param inputSbgnmlFile - * the input file. - * + * @param filename The filename of the input file. + * @param inputSbgnmlFile the input file. * @return valid model parsed from the file - * @throws InvalidInputDataExecption - * thrown when input file is invalid + * @throws InvalidInputDataExecption thrown when input file is invalid */ public Model createModel(final String filename, final File inputSbgnmlFile) throws InvalidInputDataExecption { @@ -126,23 +117,7 @@ public class SbgnmlXmlParser { elementParser = new ElementParser(renderParser, model); reactionParser = new ReactionParser(renderParser, model); - RestAnnotationParser rap = new RestAnnotationParser(); - - if (map.getNotes() != null && map.getNotes().getAny().size() > 0) { - try { - String notes = "<notes>" + XmlParser.nodeToString(map.getNotes().getAny().get(0).getParentNode(), true) - + "</notes>"; - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - dbf.setNamespaceAware(true); - DocumentBuilder db; - db = dbf.newDocumentBuilder(); - Document doc = db.parse(new ByteArrayInputStream(notes.getBytes())); - - model.setNotes(rap.getNotes(doc.getFirstChild())); - } catch (final Exception e) { - logger.warn("Problem with extracting map notes", e); - } - } + model.setNotes(notesConverter.parseNotes(map.getNotes())); elementParser.adjustSizeOfElements(map); @@ -225,11 +200,9 @@ public class SbgnmlXmlParser { /** * Method used to compute height and width of the model. - * - * @param map - * Map parsed from SBGN-ML file - * @param model - * Model to be updated + * + * @param map Map parsed from SBGN-ML file + * @param model Model to be updated */ private void setModelSize(final Map map, final Model model) { if (map.getBbox() != null) { @@ -351,11 +324,9 @@ public class SbgnmlXmlParser { /** * Finds a compartment where element should be located (base on the * coordinates). - * - * @param child - * {@link Element} for which we want to find compartment - * @param model - * {@link Model} where we look for a compartment + * + * @param child {@link Element} for which we want to find compartment + * @param model {@link Model} where we look for a compartment * @return parent {@link Compartment} */ private Compartment findParentCompartment(final Element child, final Model model) { diff --git a/converter-SBGNML/src/main/java/lcsb/mapviewer/converter/model/sbgnml/parser/ElementParser.java b/converter-SBGNML/src/main/java/lcsb/mapviewer/converter/model/sbgnml/parser/ElementParser.java index 20aa6fdb5e4691a4715c6b2cb1d7981f54f22333..9c96a1fc768ee3c90ed83ea697a38e9bb7a12c62 100644 --- a/converter-SBGNML/src/main/java/lcsb/mapviewer/converter/model/sbgnml/parser/ElementParser.java +++ b/converter-SBGNML/src/main/java/lcsb/mapviewer/converter/model/sbgnml/parser/ElementParser.java @@ -72,6 +72,8 @@ public class ElementParser extends GlyphParser { private final Model model; + private final NotesConverter notesConverter = new NotesConverter(); + public ElementParser(final RenderParser renderParser, final Model model) { this.renderParser = renderParser; this.model = model; @@ -179,6 +181,10 @@ public class ElementParser extends GlyphParser { compartment.setFillColor(COMPARTMENT_COLOR); compartment.setBorderColor(COMPARTMENT_COLOR); + if (glyph.getCompartmentOrder() != null) { + compartment.setZ(Math.round(glyph.getCompartmentOrder())); + } + if (glyph.getLabel() != null && glyph.getLabel().getBbox() != null) { compartment.setNameX(glyph.getLabel().getBbox().getX()); compartment.setNameY(glyph.getLabel().getBbox().getY()); @@ -246,6 +252,11 @@ public class ElementParser extends GlyphParser { element.setName(""); } + element.setNotes(notesConverter.parseNotes(g.getNotes())); + if (g.getCompartmentOrder() != null) { + element.setZ(Math.round(g.getCompartmentOrder())); + } + if (element instanceof Species) { final Species newSpecies = (Species) element; // Add species to parent complex if there is one @@ -448,8 +459,6 @@ public class ElementParser extends GlyphParser { * Method used to parse state variable. * * @param stateVariable unit of information glyph from sbgn-ml file - * @throws Exception Exception is thrown if state variable is parsed for species other - * than Protein */ private Residue stateVariableToResidue(final Glyph stateVariable) { if (stateVariable.getState() != null && (stateVariable.getState().getVariable() == null diff --git a/converter-SBGNML/src/main/java/lcsb/mapviewer/converter/model/sbgnml/parser/NotesConverter.java b/converter-SBGNML/src/main/java/lcsb/mapviewer/converter/model/sbgnml/parser/NotesConverter.java new file mode 100644 index 0000000000000000000000000000000000000000..4db5742a0d245cab88137dbd7cc21491f6429335 --- /dev/null +++ b/converter-SBGNML/src/main/java/lcsb/mapviewer/converter/model/sbgnml/parser/NotesConverter.java @@ -0,0 +1,62 @@ +package lcsb.mapviewer.converter.model.sbgnml.parser; + +import lcsb.mapviewer.common.XmlParser; +import lcsb.mapviewer.converter.model.celldesigner.CommonXmlParser; +import lcsb.mapviewer.converter.model.celldesigner.annotation.RestAnnotationParser; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.sbgn.bindings.SBGNBase; +import org.w3c.dom.Document; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import java.io.ByteArrayInputStream; + +public class NotesConverter { + + private final Logger logger = LogManager.getLogger(); + + private final RestAnnotationParser rap = new RestAnnotationParser(); + + public SBGNBase.Notes createNotesNode(final String notes) { + SBGNBase.Notes result = new SBGNBase.Notes(); + try { + final StringBuilder notesXml = new StringBuilder(); + notesXml.append("<html xmlns=\"http://www.w3.org/1999/xhtml\"><head><title/></head><body>"); + if (notes != null) { + notesXml.append(new CommonXmlParser().getNotesXmlContent(notes)); + } + notesXml.append("</body></html>"); + + final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setNamespaceAware(true); + final DocumentBuilder db; + db = dbf.newDocumentBuilder(); + final Document doc = db.parse(new ByteArrayInputStream(notesXml.toString().getBytes())); + + result.getAny().add((org.w3c.dom.Element) (doc.getFirstChild())); + } catch (final Exception e) { + logger.warn("Problem with processing notes"); + } + return result; + } + + public String parseNotes(final SBGNBase.Notes notesNode) { + if (notesNode != null && !notesNode.getAny().isEmpty()) { + try { + String notes = "<notes>" + XmlParser.nodeToString(notesNode.getAny().get(0).getParentNode(), true) + + "</notes>"; + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setNamespaceAware(true); + DocumentBuilder db; + db = dbf.newDocumentBuilder(); + Document doc = db.parse(new ByteArrayInputStream(notes.getBytes())); + + return rap.getNotes(doc.getFirstChild()); + } catch (final Exception e) { + logger.warn("Problem with extracting map notes", e); + } + } + return ""; + } +} diff --git a/converter-SBGNML/src/test/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlTestFunctions.java b/converter-SBGNML/src/test/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlTestFunctions.java index be2f8bb72001771afb63b3f6f5ff7ff598d31385..5f38baf0e8e31e2be6d4a8d59ecc2b81d39651fe 100644 --- a/converter-SBGNML/src/test/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlTestFunctions.java +++ b/converter-SBGNML/src/test/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlTestFunctions.java @@ -1,20 +1,5 @@ package lcsb.mapviewer.converter.model.sbgnml; -import java.awt.Color; -import java.awt.Desktop; -import java.awt.geom.Point2D; -import java.io.ByteArrayInputStream; -import java.io.File; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.junit.Rule; -import org.sbgn.GlyphClazz; -import org.sbgn.bindings.Bbox; -import org.sbgn.bindings.Glyph; - import lcsb.mapviewer.common.tests.TestUtils; import lcsb.mapviewer.common.tests.UnitTestFailedWatcher; import lcsb.mapviewer.converter.Converter; @@ -28,6 +13,8 @@ import lcsb.mapviewer.model.graphics.HorizontalAlign; import lcsb.mapviewer.model.graphics.VerticalAlign; import lcsb.mapviewer.model.map.Drawable; import lcsb.mapviewer.model.map.InconsistentModelException; +import lcsb.mapviewer.model.map.compartment.Compartment; +import lcsb.mapviewer.model.map.compartment.SquareCompartment; import lcsb.mapviewer.model.map.model.Model; import lcsb.mapviewer.model.map.species.Complex; import lcsb.mapviewer.model.map.species.Drug; @@ -35,23 +22,36 @@ import lcsb.mapviewer.model.map.species.Element; import lcsb.mapviewer.model.map.species.GenericProtein; import lcsb.mapviewer.model.map.species.Species; import lcsb.mapviewer.model.map.species.field.StructuralState; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.junit.Rule; +import org.sbgn.GlyphClazz; +import org.sbgn.bindings.Bbox; +import org.sbgn.bindings.Glyph; + +import java.awt.Color; +import java.awt.Desktop; +import java.awt.geom.Point2D; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; public class SbgnmlTestFunctions extends TestUtils { protected static Logger logger = LogManager.getLogger(); - + private static int counter = 0; + private final Converter sbgnmlConverter = new SbgnmlXmlConverter(); @Rule public UnitTestFailedWatcher unitTestFailedWatcher = new UnitTestFailedWatcher(); - private static int counter = 0; - protected void showImage(final Model model) throws Exception { String dir = Files.createTempDirectory("sbml-temp-images-dir").toFile().getAbsolutePath(); AbstractImageGenerator.Params params = new AbstractImageGenerator.Params().height(model.getHeight()) .width(model.getWidth()).nested(true).scale(1).level(20).x(0).y(0).model(model); NormalImageGenerator nig = new PngImageGenerator(params); - String pathWithouExtension = dir + "/" + model.getName(); - String pngFilePath = pathWithouExtension.concat(".png"); + String pathWithoutExtension = dir + "/" + model.getName(); + String pngFilePath = pathWithoutExtension.concat(".png"); nig.saveToFile(pngFilePath); Desktop.getDesktop().open(new File(pngFilePath)); } @@ -74,6 +74,15 @@ public class SbgnmlTestFunctions extends TestUtils { return protein; } + protected Compartment createCompartment() { + SquareCompartment compartment = new SquareCompartment("id" + (counter++)); + assignLayout(compartment); + compartment.setNameHorizontalAlign(HorizontalAlign.LEFT); + compartment.setNameVerticalAlign(VerticalAlign.TOP); + + return compartment; + } + protected Drug createDrug() { Drug drug = new Drug("id" + (counter++)); assignLayout(drug); @@ -114,8 +123,6 @@ public class SbgnmlTestFunctions extends TestUtils { return structuralState; } - private Converter sbgnmlConverter = new SbgnmlXmlConverter(); - protected Model serializeAndCleanOverSbgn(final Model model) throws InconsistentModelException, ConverterException, InvalidInputDataExecption { String sbgn = sbgnmlConverter.model2String(model); // logger.debug(sbgn); @@ -125,10 +132,14 @@ public class SbgnmlTestFunctions extends TestUtils { model2.setIdModel(model.getIdModel()); model2.setName(model.getName()); for (final Drawable d : model.getDrawables()) { - d.setZ(null); + if (!(d instanceof Element)) { + d.setZ(null); + } } for (final Drawable d : model2.getDrawables()) { - d.setZ(null); + if (!(d instanceof Element)) { + d.setZ(null); + } } for (final Species e : model.getSpeciesList()) { e.setInitialAmount(null); diff --git a/converter-SBGNML/src/test/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlXmlExporterTest.java b/converter-SBGNML/src/test/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlXmlExporterTest.java index 6db64a2a48370df28d1727e259fd2de15baec58c..bcd816d33ff55997e44fdca3975f1632689ffb36 100644 --- a/converter-SBGNML/src/test/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlXmlExporterTest.java +++ b/converter-SBGNML/src/test/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlXmlExporterTest.java @@ -1,22 +1,9 @@ package lcsb.mapviewer.converter.model.sbgnml; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import java.awt.geom.Point2D; -import java.io.File; -import java.io.PrintWriter; - -import org.junit.Test; -import org.sbgn.ArcClazz; -import org.sbgn.GlyphClazz; -import org.sbgn.SbgnUtil; - import lcsb.mapviewer.common.geometry.PointTransformation; import lcsb.mapviewer.converter.Converter; import lcsb.mapviewer.model.graphics.PolylineData; +import lcsb.mapviewer.model.map.compartment.Compartment; import lcsb.mapviewer.model.map.model.Model; import lcsb.mapviewer.model.map.model.ModelComparator; import lcsb.mapviewer.model.map.model.ModelFullIndexed; @@ -29,6 +16,19 @@ import lcsb.mapviewer.model.map.species.Drug; import lcsb.mapviewer.model.map.species.GenericProtein; import lcsb.mapviewer.model.map.species.Ion; import lcsb.mapviewer.modelutils.map.ElementUtils; +import org.junit.Test; +import org.sbgn.ArcClazz; +import org.sbgn.GlyphClazz; +import org.sbgn.SbgnUtil; + +import java.awt.geom.Point2D; +import java.io.File; +import java.io.PrintWriter; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; public class SbgnmlXmlExporterTest extends SbgnmlTestFunctions { @@ -68,7 +68,7 @@ public class SbgnmlXmlExporterTest extends SbgnmlTestFunctions { private static Reaction createReaction(final Class<? extends Reaction> clazz) throws Exception { - Reaction reaction = clazz.getConstructor(String.class).newInstance(new Object[] { "re" + (counter++) }); + Reaction reaction = clazz.getConstructor(String.class).newInstance("re" + (counter++)); Ion ion = createIon(counter++); Ion ion2 = createIon(counter); @@ -138,6 +138,19 @@ public class SbgnmlXmlExporterTest extends SbgnmlTestFunctions { assertEquals(0, new ModelComparator().compare(model, model2)); } + @Test + public void importExportNotes() throws Exception { + GenericProtein protein = createProtein(); + protein.setNotes("hello world"); + Model model = new ModelFullIndexed(null); + model.setWidth(2000); + model.setHeight(2000); + model.addElement(protein); + + Model model2 = serializeAndCleanOverSbgn(model); + assertEquals(0, new ModelComparator().compare(model, model2)); + } + @Test public void testExportWithWarning() throws Exception { Converter sbgnmlConverter = new SbgnmlXmlConverter(); @@ -159,4 +172,23 @@ public class SbgnmlXmlExporterTest extends SbgnmlTestFunctions { assertTrue(SbgnUtil.isValid(tempFile)); } + @Test + public void importExportZ() throws Exception { + GenericProtein protein = createProtein(); + protein.setZ(3); + + Compartment compartment = createCompartment(); + compartment.setZ(4); + compartment.addElement(protein); + + Model model = new ModelFullIndexed(null); + model.setWidth(2000); + model.setHeight(2000); + model.addElement(protein); + model.addElement(compartment); + + Model model2 = serializeAndCleanOverSbgn(model); + assertEquals(0, new ModelComparator().compare(model, model2)); + } + } diff --git a/converter-graphics/pom.xml b/converter-graphics/pom.xml index b91e1358f054ddd9e7195f4d0b217f3d00db621c..b930fb55b0996679a65c882e6ff86bc040073fdf 100644 --- a/converter-graphics/pom.xml +++ b/converter-graphics/pom.xml @@ -5,7 +5,7 @@ <parent> <groupId>lcsb.mapviewer</groupId> <artifactId>parent</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </parent> <artifactId>converter-graphics</artifactId> <name>MapViewer graphics converter</name> @@ -18,13 +18,13 @@ <dependency> <groupId>lcsb.mapviewer</groupId> <artifactId>model</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </dependency> <dependency> <groupId>lcsb.mapviewer</groupId> <artifactId>model-command</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </dependency> <!-- Log4J2 --> diff --git a/converter-sbml/pom.xml b/converter-sbml/pom.xml index 3d3504367c6360edd74c871edba2d1b787a07b99..dc07a47f36ff66bd91c50cef13f3e4191038ebf7 100644 --- a/converter-sbml/pom.xml +++ b/converter-sbml/pom.xml @@ -7,7 +7,7 @@ <parent> <groupId>lcsb.mapviewer</groupId> <artifactId>parent</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </parent> <artifactId>converter-sbml</artifactId> <name>converter-sbml</name> @@ -40,22 +40,22 @@ <dependency> <groupId>lcsb.mapviewer</groupId> <artifactId>model</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </dependency> <dependency> <groupId>lcsb.mapviewer</groupId> <artifactId>model-command</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </dependency> <dependency> <groupId>lcsb.mapviewer</groupId> <artifactId>converter-CellDesigner</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </dependency> <dependency> <groupId>lcsb.mapviewer</groupId> <artifactId>converter</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </dependency> <!-- Log4J2 --> @@ -167,7 +167,7 @@ <dependency> <groupId>lcsb.mapviewer</groupId> <artifactId>converter-graphics</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> <scope>test</scope> </dependency> diff --git a/converter/pom.xml b/converter/pom.xml index 166b0ab0dd8d01412acf79df838389bca06f6201..2b7328f0f48cea06e1493e7147f0d86443bd4102 100644 --- a/converter/pom.xml +++ b/converter/pom.xml @@ -5,7 +5,7 @@ <parent> <groupId>lcsb.mapviewer</groupId> <artifactId>parent</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </parent> <artifactId>converter</artifactId> @@ -15,7 +15,7 @@ <dependency> <groupId>lcsb.mapviewer</groupId> <artifactId>model</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </dependency> <dependency> <groupId>xerces</groupId> diff --git a/converter/src/main/java/lcsb/mapviewer/converter/ComplexZipConverter.java b/converter/src/main/java/lcsb/mapviewer/converter/ComplexZipConverter.java index b32fd50e3cba1e864ad7dab3708b26c6cb86907c..3c320b72e1dc3aba3ba6ee53c0605dd595d237a1 100644 --- a/converter/src/main/java/lcsb/mapviewer/converter/ComplexZipConverter.java +++ b/converter/src/main/java/lcsb/mapviewer/converter/ComplexZipConverter.java @@ -1,25 +1,5 @@ package lcsb.mapviewer.converter; -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.lang.reflect.Modifier; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; - -import org.apache.commons.io.FilenameUtils; -import org.apache.commons.io.IOUtils; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - import lcsb.mapviewer.common.TextFileUtils; import lcsb.mapviewer.common.exception.InvalidArgumentException; import lcsb.mapviewer.common.exception.InvalidClassException; @@ -31,6 +11,7 @@ import lcsb.mapviewer.converter.zip.ModelZipEntryFile; import lcsb.mapviewer.converter.zip.ZipEntryFile; import lcsb.mapviewer.converter.zip.ZipEntryFileFactory; import lcsb.mapviewer.model.cache.UploadedFileEntry; +import lcsb.mapviewer.model.map.compartment.Compartment; import lcsb.mapviewer.model.map.layout.ReferenceGenomeType; import lcsb.mapviewer.model.map.model.ElementSubmodelConnection; import lcsb.mapviewer.model.map.model.Model; @@ -45,14 +26,32 @@ import lcsb.mapviewer.model.map.species.Species; import lcsb.mapviewer.model.overlay.DataOverlay; import lcsb.mapviewer.model.overlay.DataOverlayType; import lcsb.mapviewer.model.overlay.InvalidDataOverlayException; +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.io.IOUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Modifier; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; /** * This class allows to create complex {@link Model} that contains submaps. It's * written in generic way and use {@link Converter} as a class to parse single * submap. - * + * * @author Piotr Gawron - * */ public class ComplexZipConverter { @@ -64,19 +63,19 @@ public class ComplexZipConverter { /** * Default class logger. */ - private static Logger logger = LogManager.getLogger(); + private static final Logger logger = LogManager.getLogger(); + private static final String IMMEDIATE_LINK_PREFIX = "IMMEDIATE_LINK:"; /** * Class used to create single submap from a file. */ - private Class<? extends Converter> converterClazz; + private final Class<? extends Converter> converterClazz; /** * Default constructor. Checks if the class given in the parameter is proper * {@link Converter} implementation. - * - * @param clazz - * {@link Converter} class used for creation of the single submap + * + * @param clazz {@link Converter} class used for creation of the single submap */ public ComplexZipConverter(final Class<? extends Converter> clazz) { if (Modifier.isAbstract(clazz.getModifiers())) { @@ -92,13 +91,11 @@ public class ComplexZipConverter { /** * Creates complex {@link Model} that contains submaps. - * - * @param params - * {@link ComplexZipConverterParams object} with information about data - * from which result is going to be created + * + * @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 + * @throws InvalidInputDataExecption thrown when there is a problem with accessing input data */ public Model createModel(final ComplexZipConverterParams params) throws InvalidInputDataExecption, ConverterException { try { @@ -133,7 +130,7 @@ public class ComplexZipConverter { } else if (zef instanceof GlyphZipEntryFile) { continue; } else if (!isIgnoredFile(entry.getName())) { - throw new NotImplementedException("Unknwon entry type: " + zef.getClass()); + throw new NotImplementedException("Unknown entry type: " + zef.getClass()); } } } @@ -156,6 +153,9 @@ public class ComplexZipConverter { for (final Reaction reaction : mappingModel.getReactions()) { processReaction(mapping, nameModelMap, result, reaction); } + for (final Species species : mappingModel.getSpeciesList()) { + processSpecies(species, nameModelMap); + } } return result; } catch (final IOException e) { @@ -163,6 +163,37 @@ public class ComplexZipConverter { } } + private void processSpecies(final Species species, final Map<String, Model> nameModelMap) { + String notes = species.getNotes(); + if (notes != null) { + String[] lines = notes.split("\n"); + for (String line : lines) { + line = line.trim(); + if (line.startsWith(IMMEDIATE_LINK_PREFIX)) { + String link = line.replace(IMMEDIATE_LINK_PREFIX, "").trim(); + + Compartment compartment = species.getCompartment(); + if (compartment == null) { + logger.warn("[SUBMODEL MAPPING] Species {} in mapping file doesn't start inside compartment. Skipped. Link skipped", + species.getElementId()); + } else { + String modelName = compartment.getName().toLowerCase(); + Model model = nameModelMap.get(modelName); + if (model == null) { + throw new InvalidArgumentException("Mapping file references to " + modelName + " submodel. But such model doesn't exist"); + } + Element elementToChange = model.getElementByElementId(species.getName()); + if (elementToChange == null) { + throw new InvalidArgumentException("Mapping file references to element with alias: " + species.getName() + + ". But such element doesn't exist"); + } + elementToChange.setImmediateLink(link); + } + } + } + } + } + protected boolean isIgnoredFile(final String name) { if (name == null) { return true; @@ -170,53 +201,48 @@ public class ComplexZipConverter { return true; } else if (name.startsWith(".DS_Store") || name.endsWith(".DS_Store")) { return true; - } else if (name.startsWith("__MACOSX")) { - return true; + } else { + return name.startsWith("__MACOSX"); } - return false; } /** * Process a single reaction in mapping file (transforming 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 + * + * @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(final String mapping, final Map<String, Model> nameModelMap, final Model topModel, final Reaction reaction) { if (reaction.getReactants().size() > 1) { - logger.warn("[SUBMODEL MAPPING] Reaction " + reaction.getIdReaction() + " in mapping file (" + mapping - + ") contains too many reactants. Skipped"); + logger.warn("[SUBMODEL MAPPING] Reaction {} in mapping file ({}) contains too many reactants. Skipped", + reaction.getIdReaction(), mapping); } 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"); + logger.warn("[SUBMODEL MAPPING] Reaction {} in mapping file ({}) contains too many products. Skipped", + reaction.getIdReaction(), mapping); + } else if (!reaction.getModifiers().isEmpty()) { + logger.warn("[SUBMODEL MAPPING] Reaction {} in mapping file ({}) contains modifiers. Skipped", + reaction.getIdReaction(), mapping); } 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"); + logger.warn("[SUBMODEL MAPPING] Reaction {} in mapping file ({}) contains doesn't start in species. Skipped", + reaction.getIdReaction(), mapping); } else if (!(toAlias instanceof Species)) { - logger.warn("[SUBMODEL MAPPING] Reaction " + reaction.getIdReaction() + " in mapping file (" + mapping - + ") contains doesn't end in species. Skipped"); + logger.warn("[SUBMODEL MAPPING] Reaction {} in mapping file ({}) contains doesn't end in species. Skipped", + reaction.getIdReaction(), mapping); } 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"); + logger.warn("[SUBMODEL MAPPING] Reaction {} in mapping file ({}) contains doesn't start inside complex. Skipped", + reaction.getIdReaction(), mapping); } 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"); + logger.warn("[SUBMODEL MAPPING] Reaction {} in mapping file ({}) contains doesn't end inside complex. Skipped", + reaction.getIdReaction(), mapping); } else { if (complexTo == null) { complexTo = (Complex) toAlias; @@ -226,11 +252,9 @@ public class ComplexZipConverter { 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"); + 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"); + throw new InvalidArgumentException("Mapping file references to " + toName + " submodel. But such model doesn't exist"); } Element source = fromModel.getElementByElementId(fromAlias.getName()); if (source == null) { @@ -260,11 +284,9 @@ public class ComplexZipConverter { /** * 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} + * + * @param params parameters to validate + * @param zipFile original {@link ZipFile} * @return name of the file containing mapping between submodels */ protected String validateSubmodelInformation(final ComplexZipConverterParams params, final ZipFile zipFile) { @@ -313,22 +335,17 @@ public class ComplexZipConverter { /** * Transforms {@link LayoutZipEntryFile} into {@link DataOverlay}. - * - * @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 + * + * @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 DataOverlay} for a given {@link LayoutZipEntryFile} - * @throws IOException - * thrown when there is a problem with accessing {@link ZipFile} + * @throws IOException thrown when there is a problem with accessing {@link ZipFile} */ public DataOverlay layoutZipEntryFileToLayout(final ComplexZipConverterParams params, final ZipFile zipFile, final ZipEntry entry, - final LayoutZipEntryFile layoutEntry, final int order) throws IOException, InvalidInputDataExecption { + final LayoutZipEntryFile layoutEntry, final int order) throws IOException, InvalidInputDataExecption { DataOverlay layout = new DataOverlay(); layout.setDescription(layoutEntry.getDescription()); UploadedFileEntry fileEntry = new UploadedFileEntry(); @@ -376,14 +393,11 @@ public class ComplexZipConverter { /** * Copy file from zip entry into temporary file. - * - * @param zipFile - * input zip file - * @param entry - * entry in the zip 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 + * @throws IOException thrown when there is a problem with input or output file */ protected File saveFileFromZipFile(final ZipFile zipFile, final ZipEntry entry) throws IOException { InputStream is = zipFile.getInputStream(entry); @@ -401,17 +415,15 @@ public class ComplexZipConverter { /** * Creates instance of {@link Converter} used as a template parameter for this * class instantiation. - * + * * @return instance of {@link Converter} */ protected Converter createConverterInstance() { Converter converter; try { converter = converterClazz.newInstance(); - } catch (final InstantiationException e) { - throw new InvalidClassException("Problem with instantation of the class: " + converterClazz, e); - } catch (final IllegalAccessException e) { - throw new InvalidClassException("Problem with instantation of the class: " + converterClazz, e); + } catch (final InstantiationException | IllegalAccessException e) { + throw new InvalidClassException("Problem with instantiation of the class: " + converterClazz, e); } return converter; } diff --git a/converter/src/test/java/lcsb/mapviewer/converter/ComplexZipConverterTest.java b/converter/src/test/java/lcsb/mapviewer/converter/ComplexZipConverterTest.java index 504c7c05ef9ca53ae319aabef921634de3ac1141..bb16914c1fcbac096fcae43f96ababe675c71b30 100644 --- a/converter/src/test/java/lcsb/mapviewer/converter/ComplexZipConverterTest.java +++ b/converter/src/test/java/lcsb/mapviewer/converter/ComplexZipConverterTest.java @@ -1,20 +1,5 @@ package lcsb.mapviewer.converter; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import java.io.ByteArrayInputStream; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; - import lcsb.mapviewer.common.exception.InvalidArgumentException; import lcsb.mapviewer.common.exception.InvalidClassException; import lcsb.mapviewer.converter.zip.LayoutZipEntryFile; @@ -24,6 +9,20 @@ import lcsb.mapviewer.model.map.model.ModelSubmodelConnection; import lcsb.mapviewer.model.map.model.SubmodelType; import lcsb.mapviewer.model.map.species.Element; import lcsb.mapviewer.model.overlay.DataOverlay; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +import java.io.ByteArrayInputStream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; public class ComplexZipConverterTest extends ConverterTestFunctions { @@ -85,6 +84,7 @@ public class ComplexZipConverterTest extends ConverterTestFunctions { assertNotNull(al1.getSubmodel()); assertEquals(SubmodelType.DOWNSTREAM_TARGETS, al1.getSubmodel().getType()); assertEquals(s1Model, al1.getSubmodel().getSubmodel().getModel()); + assertNotNull(al1.getImmediateLink()); Element al2 = model.getElementByElementId("sa2"); assertNull(al2.getSubmodel()); diff --git a/converter/src/test/java/lcsb/mapviewer/converter/MockConverter.java b/converter/src/test/java/lcsb/mapviewer/converter/MockConverter.java index 3bdba61b86980f3da4e772e32976fede9fad63bc..192a769747572fedd6df7eb6f04d026cbf337027 100644 --- a/converter/src/test/java/lcsb/mapviewer/converter/MockConverter.java +++ b/converter/src/test/java/lcsb/mapviewer/converter/MockConverter.java @@ -1,11 +1,8 @@ package lcsb.mapviewer.converter; -import java.io.File; -import java.io.InputStream; -import java.util.List; - import lcsb.mapviewer.common.MimeType; import lcsb.mapviewer.model.map.InconsistentModelException; +import lcsb.mapviewer.model.map.compartment.Compartment; import lcsb.mapviewer.model.map.model.Model; import lcsb.mapviewer.model.map.model.ModelFullIndexed; import lcsb.mapviewer.model.map.reaction.Product; @@ -17,6 +14,10 @@ import lcsb.mapviewer.model.map.species.GenericProtein; import lcsb.mapviewer.model.map.species.Phenotype; import lcsb.mapviewer.model.map.species.Species; +import java.io.File; +import java.io.InputStream; +import java.util.List; + public class MockConverter extends Converter { protected static Model modelToBeReturned = null; @@ -82,6 +83,17 @@ public class MockConverter extends Converter { r3.addReactant(new Reactant(sa7)); r3.addProduct(new Product(ca4)); result.addReaction(r3); + + Species sa8 = new Phenotype("sa8"); + sa8.setName("sa1"); + sa8.setNotes("IMMEDIATE_LINK:https://minerva.pages.uni.lu/doc/"); + result.addElement(sa8); + + Compartment c1 = new Compartment("comp1"); + c1.setName("main"); + c1.addElement(sa8); + result.addElement(c1); + return result; } diff --git a/converter/testFiles/complex_model.zip b/converter/testFiles/complex_model.zip index 2ae7cb3efb7084d6a670d8662a986fcf3f7128de..40cc4e93588a62ae39f833ac8c0c10aff11cfbac 100644 Binary files a/converter/testFiles/complex_model.zip and b/converter/testFiles/complex_model.zip differ diff --git a/frontend-js/pom.xml b/frontend-js/pom.xml index 1d13f482779250362688e619ead2ee20d1d2a456..682044db84ea0b1c7939cd3ca7490f533a363a2e 100644 --- a/frontend-js/pom.xml +++ b/frontend-js/pom.xml @@ -7,7 +7,7 @@ <parent> <groupId>lcsb.mapviewer</groupId> <artifactId>parent</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </parent> <artifactId>frontend-js</artifactId> <name>frontend-js</name> diff --git a/frontend-js/src/main/js/gui/leftPanel/GenericSearchPanel.js b/frontend-js/src/main/js/gui/leftPanel/GenericSearchPanel.js index 68e4d518c999c09233b6f79c6f9204e97250576a..c19b9c9e1231d5f7207622ff130f55a501f8a672 100644 --- a/frontend-js/src/main/js/gui/leftPanel/GenericSearchPanel.js +++ b/frontend-js/src/main/js/gui/leftPanel/GenericSearchPanel.js @@ -19,6 +19,7 @@ var SearchBioEntityGroup = require('../../map/data/SearchBioEntityGroup'); var logger = require('../../logger'); var Functions = require('../../Functions'); var SearchMapBioEntityGroup = require("../../map/data/SearchMapBioEntityGroup"); +var AbstractDbOverlay = require("../../map/overlay/AbstractDbOverlay"); var QueryType = require("../../map/overlay/AbstractDbOverlay").QueryType; /** @@ -72,6 +73,28 @@ function GenericSearchPanel(params) { } }); }); + + self.getOverlayDb().addListener("onSearch", function (data) { + if (data.arg.type === AbstractDbOverlay.QueryType.SEARCH_BY_COORDINATES) { + if (data.arg.identifiedElements.length > 0 && data.arg.identifiedElements[0].length > 0) { + var identifiedElement = data.arg.identifiedElements[0][0]; + var model = self.getMap().getSubmapById(identifiedElement.getModelId()).getModel(); + return model.getByIdentifiedElement(identifiedElement, true).then(function (element) { + if (element instanceof Alias) { + var link = element.getImmediateLink(); + if (link != null) { + var tab = window.open(link, '_blank'); + if (tab) { + tab.focus(); + } else { + GuiConnector.warn('Browser prevented minerva from opening link: <a href="' + link + '" target="_blank">' + link + '</a>'); + } + } + } + }); + } + } + }); } GenericSearchPanel.prototype = Object.create(AbstractDbPanel.prototype); diff --git a/frontend-js/src/main/js/map/data/Alias.js b/frontend-js/src/main/js/map/data/Alias.js index 9abbc22e119cf957cff57fbca3fa9b458ba91aff..b0bbc8b39c31868f9699d1dbf51d41c6090245ca 100644 --- a/frontend-js/src/main/js/map/data/Alias.js +++ b/frontend-js/src/main/js/map/data/Alias.js @@ -56,6 +56,7 @@ Alias.prototype.update = function (javaObject) { return; } this.setDescription(javaObject.getDescription()); + this.setImmediateLink(javaObject.getImmediateLink()); this.setElementId(javaObject.getElementId()); this.setType(javaObject.getType()); this.setCharge(javaObject.getCharge()); @@ -94,6 +95,7 @@ Alias.prototype.update = function (javaObject) { return; } this.setDescription(javaObject.notes); + this.setImmediateLink(javaObject.immediateLink); this.setElementId(javaObject.elementId); this.setType(javaObject.type); this.setCharge(javaObject.charge); @@ -440,4 +442,21 @@ Alias.prototype.setGlyph = function (glyph) { this._glyph = glyph; }; +/** + * + * @param {string|null} immediateLink + */ +Alias.prototype.setImmediateLink = function (immediateLink) { + this._immediateLink = immediateLink; +}; + +/** + * + * @returns {string|null} + */ +Alias.prototype.getImmediateLink = function () { + return this._immediateLink; +}; + + module.exports = Alias; diff --git a/model-command/pom.xml b/model-command/pom.xml index 514a83188dea8421d9ac1a5ddc6255533eaa6244..023c9c1f0a0d1b51026c6daaf60d9aa29cd7cf6b 100644 --- a/model-command/pom.xml +++ b/model-command/pom.xml @@ -3,7 +3,7 @@ <parent> <groupId>lcsb.mapviewer</groupId> <artifactId>parent</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </parent> <artifactId>model-command</artifactId> <name>Model commands</name> @@ -16,7 +16,7 @@ <dependency> <groupId>lcsb.mapviewer</groupId> <artifactId>model</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </dependency> @@ -24,7 +24,7 @@ <dependency> <groupId>lcsb.mapviewer</groupId> <artifactId>converter-CellDesigner</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </dependency> <!-- Log4J2--> diff --git a/model/pom.xml b/model/pom.xml index f8fc261bbf464cca91d59201a2b72c7b3bd18795..5172f0a04eb9f7c0337ddd6b6b26c9f65647a683 100644 --- a/model/pom.xml +++ b/model/pom.xml @@ -5,7 +5,7 @@ <parent> <groupId>lcsb.mapviewer</groupId> <artifactId>parent</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </parent> <artifactId>model</artifactId> <name>model MapViewer</name> @@ -15,7 +15,7 @@ <dependency> <groupId>lcsb.mapviewer</groupId> <artifactId>commons</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </dependency> <!-- Java xml serialization --> diff --git a/model/src/main/java/lcsb/mapviewer/model/map/model/ElementByIdComparator.java b/model/src/main/java/lcsb/mapviewer/model/map/model/ElementByIdComparator.java new file mode 100644 index 0000000000000000000000000000000000000000..a59f3de08839fd0c05a9b11b5ba0cac761d7a702 --- /dev/null +++ b/model/src/main/java/lcsb/mapviewer/model/map/model/ElementByIdComparator.java @@ -0,0 +1,18 @@ +package lcsb.mapviewer.model.map.model; + +import lcsb.mapviewer.common.comparator.StringComparator; +import lcsb.mapviewer.model.map.species.Element; + +import java.util.Comparator; + +public class ElementByIdComparator implements Comparator<Element> { + private final StringComparator comparator = new StringComparator(); + + @Override + public int compare(final Element o1, final Element o2) { + if (comparator.compare(o1.getElementId(), o2.getElementId()) == 0) { + return o1.getId() - o2.getId(); + } + return comparator.compare(o1.getElementId(), o2.getElementId()); + } +} diff --git a/model/src/main/java/lcsb/mapviewer/model/map/model/Model.java b/model/src/main/java/lcsb/mapviewer/model/map/model/Model.java index 0a694e9307b033c47adc5a9a39493d008385082a..b9c683193f3b421dbe0a78938610e3115966f65c 100644 --- a/model/src/main/java/lcsb/mapviewer/model/map/model/Model.java +++ b/model/src/main/java/lcsb/mapviewer/model/map/model/Model.java @@ -1,13 +1,6 @@ package lcsb.mapviewer.model.map.model; -import java.util.Calendar; -import java.util.Collection; -import java.util.Comparator; -import java.util.List; -import java.util.Set; - import com.fasterxml.jackson.annotation.JsonIgnore; - import lcsb.mapviewer.model.Project; import lcsb.mapviewer.model.map.BioEntity; import lcsb.mapviewer.model.map.Drawable; @@ -25,13 +18,18 @@ import lcsb.mapviewer.model.map.species.Complex; import lcsb.mapviewer.model.map.species.Element; import lcsb.mapviewer.model.map.species.Species; +import java.util.Calendar; +import java.util.Collection; +import java.util.Comparator; +import java.util.List; +import java.util.Set; + /** * This interface defines functionality that the model container class should * implement to access data efficiently. It shouldn't be implemented by data * model. - * + * * @author Piotr Gawron - * */ public interface Model { @@ -45,45 +43,38 @@ public interface Model { /** * Adds element to the model. - * - * @param element - * element to add + * + * @param element element to add */ void addElement(final Element element); /** - * * @return model width */ double getWidth(); /** * Sets model width. - * - * @param width - * new model width + * + * @param width new model width */ void setWidth(final double width); /** * Sets model width. * - * @param text - * new model width + * @param text new model width */ @JsonIgnore void setWidth(final String text); /** - * - * @param width - * new {@link ModelData#width} + * @param width new {@link ModelData#width} */ @JsonIgnore void setWidth(final int width); /** - * * @return model height */ double getHeight(); @@ -91,24 +82,20 @@ public interface Model { /** * Sets model height. * - * @param height - * new model height + * @param height new model height */ void setHeight(final double height); /** * Sets model height. * - * @param text - * new model height + * @param text new model height */ @JsonIgnore void setHeight(final String text); /** - * - * @param height - * new {@link ModelData#height} + * @param height new {@link ModelData#height} */ @JsonIgnore void setHeight(final int height); @@ -121,9 +108,7 @@ public interface Model { Set<Element> getElements(); /** - * - * @param elements - * new {@link ModelData#elements} collection + * @param elements new {@link ModelData#elements} collection */ void setElements(final Set<Element> elements); @@ -131,10 +116,8 @@ public interface Model { * Returns element with the given element identifier * ({@link Element#elementId} ). * - * @param idElement - * element identifier - * @param <T> - * type of the object to be returned + * @param idElement element identifier + * @param <T> type of the object to be returned * @return {@link Element} with the given id */ <T extends Element> T getElementByElementId(final String idElement); @@ -142,8 +125,7 @@ public interface Model { /** * Adds reaction to the model. * - * @param reaction - * reaction to add + * @param reaction reaction to add */ void addReaction(final Reaction reaction); @@ -162,13 +144,11 @@ public interface Model { /** * Adds layer to the model. * - * @param layer - * object to add + * @param layer object to add */ void addLayer(final Layer layer); /** - * * @return set of layers */ Set<Layer> getLayers(); @@ -176,13 +156,11 @@ public interface Model { /** * Adds list of elements into model. * - * @param elements - * list of elements + * @param elements list of elements */ void addElements(final Collection<? extends Element> elements); /** - * * @return short description of the model */ String getNotes(); @@ -190,16 +168,14 @@ public interface Model { /** * Sets new short description of the model. * - * @param notes - * new short description + * @param notes new short description */ void setNotes(final String notes); /** * Returns reaction with the id given in the parameter. * - * @param idReaction - * reaction identifier ({@link Reaction#idReaction}) + * @param idReaction reaction identifier ({@link Reaction#idReaction}) * @return reaction with the id given in the parameter */ Reaction getReactionByReactionId(final String idReaction); @@ -207,24 +183,21 @@ public interface Model { /** * Adds set of layers to the model. * - * @param layers - * object to add + * @param layers object to add */ void addLayers(final Collection<Layer> layers); /** * Adds {@link ElementGroup} to the model. * - * @param elementGroup - * object to add + * @param elementGroup object to add */ void addElementGroup(final ElementGroup elementGroup); /** * Adds {@link BlockDiagram} to the model. * - * @param blockDiagram - * object to add + * @param blockDiagram object to add */ void addBlockDiagream(final BlockDiagram blockDiagram); @@ -235,8 +208,7 @@ public interface Model { String getIdModel(); /** - * @param idModel - * the idModel to set + * @param idModel the idModel to set * @see Model#idModel */ void setIdModel(final String idModel); @@ -248,8 +220,7 @@ public interface Model { int getTileSize(); /** - * @param tileSize - * the tileSize to set + * @param tileSize the tileSize to set * @see ModelData#tileSize */ void setTileSize(final int tileSize); @@ -261,8 +232,7 @@ public interface Model { int getZoomLevels(); /** - * @param zoomLevels - * the zoomLevels to set + * @param zoomLevels the zoomLevels to set * @see ModelData#zoomLevels */ void setZoomLevels(final int zoomLevels); @@ -270,16 +240,14 @@ public interface Model { /** * Removes reaction from model. * - * @param reaction - * reaction to remove + * @param reaction reaction to remove */ void removeReaction(final Reaction reaction); /** * Removes {@link Element} from the model. * - * @param element - * element to remove + * @param element element to remove */ void removeElement(final Element element); @@ -307,16 +275,14 @@ public interface Model { /** * Adds reactions to model. * - * @param reactions2 - * list of reaction to add + * @param reactions2 list of reaction to add */ void addReactions(final List<Reaction> reactions2); /** * Returns list of elements with given name. * - * @param name - * name of the element + * @param name name of the element * @return list of elements with given name */ List<Element> getElementsByName(final String name); @@ -324,8 +290,7 @@ public interface Model { /** * Returns {@link Element} for given database identifier. * - * @param dbId - * element database identifier ({@link Element#id}) + * @param dbId element database identifier ({@link Element#id}) * @return {@link Element} for a given id */ <T extends Element> T getElementByDbId(final Integer dbId); @@ -333,8 +298,7 @@ public interface Model { /** * Returns {@link Reaction} for given database identifier. * - * @param dbId - * reaction database identifier ({@link Reaction#id}) + * @param dbId reaction database identifier ({@link Reaction#id}) * @return {@link Reaction} for a given id */ Reaction getReactionByDbId(final Integer dbId); @@ -354,15 +318,12 @@ public interface Model { List<Element> getElementsSortedBySize(); /** - * * @return {@link ModelData#project} */ Project getProject(); /** - * - * @param project - * new {@link ModelData#project} + * @param project new {@link ModelData#project} */ void setProject(final Project project); @@ -372,7 +333,6 @@ public interface Model { ModelData getModelData(); /** - * * @return {@link ModelData#id} */ int getId(); @@ -380,16 +340,14 @@ public interface Model { /** * Sets database identifier of the model. * - * @param id - * database identifier + * @param id database identifier */ void setId(final int id); /** * Adds submodel connection. * - * @param submodel - * submodel to add + * @param submodel submodel to add */ void addSubmodelConnection(final ModelSubmodelConnection submodel); @@ -410,8 +368,7 @@ public interface Model { /** * Sets name of the model. * - * @param name - * name of the model + * @param name name of the model */ void setName(final String name); @@ -419,19 +376,17 @@ public interface Model { * Returns {@link Model submodel} by the {@link ModelData#id database * identifier} given in the parameter. * - * @param idObject - * the {@link ModelData#id database identifier} that identifies - * submodel + * @param idObject the {@link ModelData#id database identifier} that identifies + * submodel * @return {@link Model submodel} by the {@link ModelData#id database - * identifier} given in the parameter + * identifier} given in the parameter */ Model getSubmodelById(final Integer idObject); /** * Returns submodel identified by submodel identifier. * - * @param identifier - * identifier of the model + * @param identifier identifier of the model * @return submodel identified by identifier */ Model getSubmodelById(final String identifier); @@ -447,8 +402,7 @@ public interface Model { /** * Returns connection to a submodel identified by connection name. * - * @param name - * name of the connection + * @param name name of the connection * @return connection to a submodel identified by connection name */ Model getSubmodelByConnectionName(final String name); @@ -456,8 +410,7 @@ public interface Model { /** * Returns connection to a submodel identified by connection identifier. * - * @param id - * id of the connection + * @param id id of the connection * @return connection to a submodel identified by connection identifier */ SubmodelConnection getSubmodelConnectionById(final Integer id); @@ -473,17 +426,16 @@ public interface Model { * Returns {@link Model submodel} identified by the {@link ModelData#name * model name}. It returns this 'parent' object when the names matches. * - * @param name - * name of the submodel that should be returned + * @param name name of the submodel that should be returned * @return {@link Model submodel} identified by the {@link ModelData#name - * model name} + * model name} */ Model getSubmodelByName(final String name); /** * Return list of all {@link BioEntity} in the map. This includes all * {@link Reaction reactions} and {@link Element elements}. - * + * * @return list of all {@link BioEntity} in the map */ List<BioEntity> getBioEntities(); @@ -532,25 +484,27 @@ public interface Model { void addMiriamData(final Collection<MiriamData> parseRdfNode); - public void addAuthor(final Author author); + void addAuthor(final Author author); void addAuthors(final Collection<Author> authorsFromRdf); - public List<Author> getAuthors(); + List<Author> getAuthors(); - public Calendar getCreationDate(); + Calendar getCreationDate(); - public void setCreationDate(final Calendar creationDate); + void setCreationDate(final Calendar creationDate); - public void addModificationDate(final Calendar modificationDate); + void addModificationDate(final Calendar modificationDate); - public List<Calendar> getModificationDates(); + List<Calendar> getModificationDates(); void addModificationDates(final Collection<Calendar> modificationDatesFromRdf); - void removeBioEntity(final BioEntity bioEntitiy); + void removeBioEntity(final BioEntity bioEntity); Set<Drawable> getDrawables(); Set<Drawable> getDrawables(boolean onlyVisible); + + Collection<Element> getSortedElements(); } diff --git a/model/src/main/java/lcsb/mapviewer/model/map/model/ModelFullIndexed.java b/model/src/main/java/lcsb/mapviewer/model/map/model/ModelFullIndexed.java index 2301de3071c32efbab8e4bdab8b44a885708fb5b..ffa13ff0832c8ee05f30e028ec815bcff95b131e 100644 --- a/model/src/main/java/lcsb/mapviewer/model/map/model/ModelFullIndexed.java +++ b/model/src/main/java/lcsb/mapviewer/model/map/model/ModelFullIndexed.java @@ -1,18 +1,5 @@ package lcsb.mapviewer.model.map.model; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - import lcsb.mapviewer.common.exception.InvalidArgumentException; import lcsb.mapviewer.model.Project; import lcsb.mapviewer.model.map.BioEntity; @@ -30,14 +17,25 @@ import lcsb.mapviewer.model.map.species.Complex; import lcsb.mapviewer.model.map.species.Element; import lcsb.mapviewer.model.map.species.Species; import lcsb.mapviewer.model.map.species.field.SpeciesWithModificationResidue; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; /** * This class implements {@link Model} interface. It's is very simple * implementation containing structures that index the data from * {@link ModelData} structure and provide access method to this indexed data. - * + * * @author Piotr Gawron - * */ public class ModelFullIndexed implements Model { @@ -45,31 +43,31 @@ public class ModelFullIndexed implements Model { * Default class logger. */ @SuppressWarnings("unused") - private static Logger logger = LogManager.getLogger(); + private static final Logger logger = LogManager.getLogger(); /** * Object that map {@link Element#elementId element identifier} into * {@link Element}. */ - private Map<String, Element> elementByElementId = new HashMap<>(); + private final Map<String, Element> elementByElementId = new HashMap<>(); /** * Object that map {@link Element#id element database identifier} into * {@link Element}. */ - private Map<Integer, Element> elementByDbId = new HashMap<>(); + private final Map<Integer, Element> elementByDbId = new HashMap<>(); /** * Object that map {@link Reaction#idReaction reaction identifier} into * {@link Reaction}. */ - private Map<String, Reaction> reactionByReactionId = new HashMap<>(); + private final Map<String, Reaction> reactionByReactionId = new HashMap<>(); /** * Object that map {@link Reaction#id reaction database identifier} into * {@link Reaction}. */ - private Map<Integer, Reaction> reactionByDbId = new HashMap<>(); + private final Map<Integer, Reaction> reactionByDbId = new HashMap<>(); /** * {@link ModelData} object containing "raw" data about the model. @@ -78,9 +76,8 @@ public class ModelFullIndexed implements Model { /** * Default constructor. - * - * @param model - * {@link ModelData} object containing "raw" data about the model + * + * @param model {@link ModelData} object containing "raw" data about the model */ public ModelFullIndexed(final ModelData model) { if (model == null) { @@ -202,6 +199,7 @@ public class ModelFullIndexed implements Model { result.add((Compartment) element); } } + result.sort(new ElementByIdComparator()); return result; } @@ -322,6 +320,7 @@ public class ModelFullIndexed implements Model { result.add((Species) element); } } + result.sort(new ElementByIdComparator()); return result; } @@ -333,6 +332,7 @@ public class ModelFullIndexed implements Model { result.add((Species) element); } } + result.sort(new ElementByIdComparator()); return result; } @@ -344,6 +344,7 @@ public class ModelFullIndexed implements Model { result.add((Complex) element); } } + result.sort(new ElementByIdComparator()); return result; } @@ -700,13 +701,13 @@ public class ModelFullIndexed implements Model { } @Override - public void removeBioEntity(final BioEntity bioEntitiy) { - if (bioEntitiy instanceof Reaction) { - removeReaction((Reaction) bioEntitiy); - } else if (bioEntitiy instanceof Element) { - removeElement((Element) bioEntitiy); + public void removeBioEntity(final BioEntity bioEntity) { + if (bioEntity instanceof Reaction) { + removeReaction((Reaction) bioEntity); + } else if (bioEntity instanceof Element) { + removeElement((Element) bioEntity); } else { - throw new InvalidArgumentException("Unknown class type:" + bioEntitiy); + throw new InvalidArgumentException("Unknown class type:" + bioEntity); } } @@ -731,4 +732,11 @@ public class ModelFullIndexed implements Model { } return result; } + + @Override + public Collection<Element> getSortedElements() { + List<Element> result = new ArrayList<>(getElements()); + result.sort(new ElementByIdComparator()); + return result; + } } diff --git a/model/src/main/java/lcsb/mapviewer/model/map/species/Element.java b/model/src/main/java/lcsb/mapviewer/model/map/species/Element.java index 8f06c45f1471fd924cae31d1696bad2370b0902f..55a2f2bb686f9a043efd059ab564fd9a565080ce 100644 --- a/model/src/main/java/lcsb/mapviewer/model/map/species/Element.java +++ b/model/src/main/java/lcsb/mapviewer/model/map/species/Element.java @@ -311,6 +311,11 @@ public abstract class Element implements BioEntity, Serializable, SbmlArgument { @JsonProperty(value = "references") private Set<MiriamData> miriamData = new HashSet<>(); + + @JsonProperty(value = "immediateLink") + @Column(nullable = true) + private String immediateLink; + /** * Constructor that creates a copy of the element given in the parameter. * @@ -1141,4 +1146,12 @@ public abstract class Element implements BioEntity, Serializable, SbmlArgument { public long getEntityVersion() { throw new NotImplementedException(); } + + public void setImmediateLink(final String immediateLink) { + this.immediateLink = immediateLink; + } + + public String getImmediateLink() { + return immediateLink; + } } \ No newline at end of file diff --git a/model/src/test/java/lcsb/mapviewer/model/map/model/ModelFullIndexedTest.java b/model/src/test/java/lcsb/mapviewer/model/map/model/ModelFullIndexedTest.java index c2fffd96d1f5f1f0deff454fca5711a2bf2f91aa..e868f83a9385a5a1d23a5975a5a5122eade8be26 100644 --- a/model/src/test/java/lcsb/mapviewer/model/map/model/ModelFullIndexedTest.java +++ b/model/src/test/java/lcsb/mapviewer/model/map/model/ModelFullIndexedTest.java @@ -1,21 +1,5 @@ package lcsb.mapviewer.model.map.model; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; - import lcsb.mapviewer.ModelTestFunctions; import lcsb.mapviewer.common.Configuration; import lcsb.mapviewer.common.exception.InvalidArgumentException; @@ -36,6 +20,21 @@ import lcsb.mapviewer.model.map.species.GenericProtein; import lcsb.mapviewer.model.map.species.Protein; import lcsb.mapviewer.model.map.species.Species; import lcsb.mapviewer.model.map.species.field.StructuralState; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; public class ModelFullIndexedTest extends ModelTestFunctions { @@ -543,4 +542,24 @@ public class ModelFullIndexedTest extends ModelTestFunctions { assertTrue(model.getDrawables().contains(state)); } + @Test + public void testGetSortedElements() { + ModelFullIndexed model = new ModelFullIndexed(null); + + Protein protein1 = new GenericProtein("1"); + Protein protein2 = new GenericProtein("3"); + Protein protein3 = new GenericProtein("2"); + Protein protein4 = new GenericProtein("4"); + + model.addElement(protein1); + + assertEquals(protein1, model.getSortedElements().iterator().next()); + model.addElement(protein2); + assertEquals(protein1, model.getSortedElements().iterator().next()); + model.addElement(protein3); + assertEquals(protein1, model.getSortedElements().iterator().next()); + model.addElement(protein4); + assertEquals(protein1, model.getSortedElements().iterator().next()); + } + } diff --git a/pathvisio/pom.xml b/pathvisio/pom.xml index ff92c53a0d0166baa33ac29f80770913f3c0c877..3549eb953bf6b638aed3aa88b8549427296c7468 100644 --- a/pathvisio/pom.xml +++ b/pathvisio/pom.xml @@ -5,7 +5,7 @@ <parent> <groupId>lcsb.mapviewer</groupId> <artifactId>parent</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </parent> <artifactId>pathvisio</artifactId> <name>Pathvisio plugin</name> @@ -77,26 +77,26 @@ <dependency> <groupId>lcsb.mapviewer</groupId> <artifactId>model</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </dependency> <dependency> <groupId>lcsb.mapviewer</groupId> <artifactId>converter-CellDesigner</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </dependency> <dependency> <groupId>lcsb.mapviewer</groupId> <artifactId>converter-graphics</artifactId> <scope>test</scope> - <version>18.0.8</version> + <version>18.1.0</version> </dependency> <dependency> <groupId>lcsb.mapviewer</groupId> <artifactId>model-command</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </dependency> <!-- Log4J2 --> diff --git a/pathvisio/src/main/java/lcsb/mapviewer/wikipathway/xml/ModelToGPML.java b/pathvisio/src/main/java/lcsb/mapviewer/wikipathway/xml/ModelToGPML.java index 33366ea4f4a148ffb604c598c5de7b9fa98d6a79..7efeeb482288e4cb08877a062b244c6a84e65e50 100644 --- a/pathvisio/src/main/java/lcsb/mapviewer/wikipathway/xml/ModelToGPML.java +++ b/pathvisio/src/main/java/lcsb/mapviewer/wikipathway/xml/ModelToGPML.java @@ -1,23 +1,5 @@ package lcsb.mapviewer.wikipathway.xml; -import java.awt.Color; -import java.awt.Polygon; -import java.awt.Shape; -import java.awt.geom.Ellipse2D; -import java.awt.geom.Line2D; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.text.StringEscapeUtils; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - import lcsb.mapviewer.common.XmlParser; import lcsb.mapviewer.common.exception.InvalidArgumentException; import lcsb.mapviewer.common.geometry.ColorParser; @@ -60,12 +42,28 @@ import lcsb.mapviewer.wikipathway.model.GpmlLineType; import lcsb.mapviewer.wikipathway.model.InteractionMapping; import lcsb.mapviewer.wikipathway.model.ShapeMapping; import lcsb.mapviewer.wikipathway.utils.Geo; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.text.StringEscapeUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.awt.Color; +import java.awt.Polygon; +import java.awt.Shape; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Line2D; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.HashSet; +import java.util.List; +import java.util.Set; /** * Class contains methods for ModelToGPML conversion. - * + * * @author Jan Badura - * */ public class ModelToGPML { @@ -104,15 +102,15 @@ public class ModelToGPML { /** * Parser used to convert from/to xml {@link MiriamData} annotations. */ - private ReferenceParser referenceParser; + private final ReferenceParser referenceParser; /** * Parser used to convert from/to xml (in BioPAX format) {@link MiriamData} * annotations. */ - private BiopaxParser biopaxParser; + private final BiopaxParser biopaxParser; - private ColorParser colorParser = new ColorParser(); + private final ColorParser colorParser = new ColorParser(); public ModelToGPML(final String mapName) { referenceParser = new ReferenceParser(mapName); @@ -121,7 +119,7 @@ public class ModelToGPML { /** * Returns new unique identifier for the model. - * + * * @return new unique identifier for the model */ private String getNewId() { @@ -133,9 +131,8 @@ public class ModelToGPML { * This function returns GPML Species type based on class. If it can not * recognize one of (Rna,GeneProduct,Protein,Metabolite) it will throw * {@link InvalidArgumentException}. - * - * @param species - * species for which GPML type will be returned + * + * @param species species for which GPML type will be returned * @return String - type */ private String getType(final Species species) { @@ -171,9 +168,8 @@ public class ModelToGPML { * Since in pathvisio it is impossible to set the size of group rectangle this * function calculates new rectangle for complex based on contents of this * complex. - * - * @param alias - * alias for which rectangle border is calculated + * + * @param alias alias for which rectangle border is calculated * @return rectangle border for alias */ Shape getShape(final Element alias) { @@ -237,11 +233,9 @@ public class ModelToGPML { * This function calculates {@link PolylineData} based on start {@link Reactant} * and end {@link Product}. If end or start points are to far away from their * rectangles new points are added. - * - * @param start - * reactant from which polyline starts - * @param end - * product where polyline ends + * + * @param start reactant from which polyline starts + * @param end product where polyline ends * @return {@link PolylineData} between start and end */ private PolylineData getPolyline(final Reactant start, final Product end) { @@ -280,11 +274,9 @@ public class ModelToGPML { /** * This function calculates PolylineData based on ReactionNode. - * - * @param rn - * reaction node for which polyline is calculated - * @param mainLine - * main line to which polyline is attached + * + * @param rn reaction node for which polyline is calculated + * @param mainLine main line to which polyline is attached * @return polyline for {@link ReactionNode} */ PolylineData getPolyline(final ReactionNode rn, final PolylineData mainLine) { @@ -328,13 +320,12 @@ public class ModelToGPML { /** * This function transform Compartments into Shapes (final Oval or Rectangle) * from PathVisio. - * - * @param model - * model where compartments are placed + * + * @param model model where compartments are placed * @return String that encodes all compartments in GPML format */ private String getComparments(final Model model) { - StringBuilder result = new StringBuilder(""); + StringBuilder result = new StringBuilder(); for (final Compartment compartment : model.getCompartments()) { result.append(compartmentToXml(compartment)); } @@ -342,7 +333,7 @@ public class ModelToGPML { } String compartmentToXml(final Compartment ca) { - StringBuilder comparments = new StringBuilder(""); + StringBuilder comparments = new StringBuilder(); double x = ca.getCenterX(); double y = ca.getCenterY(); double h = ca.getHeight(); @@ -374,23 +365,18 @@ public class ModelToGPML { * This function creates Interaction for other product, reactant or modifier * from main reaction. This is support function for getInteractions(Model * model). - * - * @param rn - * object representing reactant/product/modifier - * @param anchId - * identifier of the anchor where it will be connected - * @param anchors - * string builder where anchors are stored (it will be modified to add - * anchor for this element) - * @param mainLine - * line used for connecting this element + * + * @param rn object representing reactant/product/modifier + * @param anchId identifier of the anchor where it will be connected + * @param anchors string builder where anchors are stored (it will be modified to add + * anchor for this element) + * @param mainLine line used for connecting this element * @return string representing connection of this element to reaction - * @throws ConverterException - * thrown when there is a problem with conversion + * @throws ConverterException thrown when there is a problem with conversion */ private String getInteractionForAnchor(final ReactionNode rn, final String anchId, final StringBuilder anchors, final PolylineData mainLine) throws ConverterException { - StringBuilder interaction = new StringBuilder(""); + StringBuilder interaction = new StringBuilder(); PolylineData line = getPolyline(rn, mainLine); Point2D ps = line.getStartPoint(); @@ -486,16 +472,14 @@ public class ModelToGPML { /** * This function encode Species into DataNodes from GPML format. Empty complexes * are also transformed into DataNodes. - * - * @param model - * model where aliases are placed + * + * @param model model where aliases are placed * @return string representing {@link lcsb.mapviewer.wikipathway.model.DataNode - * data nodes} - * @throws ConverterException - * thrown when there is a problem with conversion + * data nodes} + * @throws ConverterException thrown when there is a problem with conversion */ protected String getDataNodes(final Model model) throws ConverterException { - StringBuilder dataNodes = new StringBuilder(""); + StringBuilder dataNodes = new StringBuilder(); for (final Species species : model.getNotComplexSpeciesList()) { if (!(species instanceof Complex) && !(species instanceof Degraded)) { @@ -657,13 +641,12 @@ public class ModelToGPML { /** * This function encode ComplexAliases into Groups from GPML format. - * - * @param model - * model where aliases are placed + * + * @param model model where aliases are placed * @return string representing groups in GPML format */ protected String getGroups(final Model model) { - StringBuilder groups = new StringBuilder(""); + StringBuilder groups = new StringBuilder(); for (final Complex complex : model.getComplexList()) { if (complex.getElements().size() > 0) { @@ -685,15 +668,13 @@ public class ModelToGPML { /** * This function encode Reactions into Interactions from GPML format. - * - * @param model - * model where reactions are placed + * + * @param model model where reactions are placed * @return string with interactions in GPML format - * @throws ConverterException - * thrown when there is a problem with conversion + * @throws ConverterException thrown when there is a problem with conversion */ protected String getInteractions(final Model model) throws ConverterException { - StringBuilder interactions = new StringBuilder(""); + StringBuilder interactions = new StringBuilder(); for (final Reaction reaction : model.getReactions()) { String reactionArrowHead = InteractionMapping.getGpmlInteractionTypeForMinervaReactionClass(reaction.getClass()) @@ -701,8 +682,8 @@ public class ModelToGPML { String lineStyle = GpmlLineType.getByLineType(reaction.getLine().getType()).getGpmlString(); - StringBuilder anchors = new StringBuilder(""); - StringBuilder tmp = new StringBuilder(""); + StringBuilder anchors = new StringBuilder(); + StringBuilder tmp = new StringBuilder(); interactions.append(" <Interaction GraphId=\"" + reaction.getIdReaction() + "\">\n"); if (reaction.getNotes() != null) { @@ -767,12 +748,12 @@ public class ModelToGPML { tmp.append(getInteractionForAnchor(modifier, getNewId(), anchors, line)); } - interactions.append(anchors.toString()); + interactions.append(anchors); interactions.append(" </Graphics>\n"); interactions.append( referenceParser.toXml(reaction.getMiriamData(), new LogMarker(ProjectLogEntryType.EXPORT_ISSUE, reaction))); interactions.append(" </Interaction>\n"); - interactions.append(tmp.toString()); + interactions.append(tmp); } return interactions.toString(); @@ -780,15 +761,13 @@ public class ModelToGPML { /** * This function returns Model in GPML format. - * - * @param model - * model to transform + * + * @param model model to transform * @return string in GPML format representing model - * @throws ConverterException - * thrown when there is a problem with conversion + * @throws ConverterException thrown when there is a problem with conversion */ public String getGPML(final Model model) throws ConverterException { - StringBuilder gpml = new StringBuilder(""); + StringBuilder gpml = new StringBuilder(); gpml.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); gpml.append("<Pathway xmlns=\"http://pathvisio.org/GPML/2013a\""); if (model.getName() != null) { @@ -845,7 +824,7 @@ public class ModelToGPML { private String getStates(final Model model) throws ConverterException { StringBuilder result = new StringBuilder(); - for (final Element element : model.getElements()) { + for (final Element element : model.getSortedElements()) { if (element instanceof SpeciesWithModificationResidue) { for (final ModificationResidue mr : ((SpeciesWithModificationResidue) element).getModificationResidues()) { result.append(modifictionResidueToState(mr)); @@ -860,7 +839,7 @@ public class ModelToGPML { } protected String getShapes(final Model model) throws ConverterException { - StringBuilder result = new StringBuilder(""); + StringBuilder result = new StringBuilder(); result.append(getComparments(model)); for (final Species species : model.getNotComplexSpeciesList()) { diff --git a/persist/pom.xml b/persist/pom.xml index d648423f8fc46eb16eca081ad11cf5978918b9ea..24678fa8391ffd3ab67ce57fb40b26d08961d182 100644 --- a/persist/pom.xml +++ b/persist/pom.xml @@ -6,7 +6,7 @@ <parent> <groupId>lcsb.mapviewer</groupId> <artifactId>parent</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </parent> <artifactId>persist</artifactId> @@ -26,7 +26,7 @@ <dependency> <groupId>lcsb.mapviewer</groupId> <artifactId>model</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </dependency> <!-- Hibernate --> diff --git a/persist/src/main/resources/db/migration/hsql/18.0.8/V18.0.8.20241213__remove_refresh_jobs.sql b/persist/src/main/resources/db/migration/hsql/18.1.0/V18.0.8.20241213__remove_refresh_jobs.sql similarity index 100% rename from persist/src/main/resources/db/migration/hsql/18.0.8/V18.0.8.20241213__remove_refresh_jobs.sql rename to persist/src/main/resources/db/migration/hsql/18.1.0/V18.0.8.20241213__remove_refresh_jobs.sql diff --git a/persist/src/main/resources/db/migration/hsql/18.0.8/V18.0.8.20241230.2__set_proper_pathway_and_compartment.sql b/persist/src/main/resources/db/migration/hsql/18.1.0/V18.0.8.20241230.2__set_proper_pathway_and_compartment.sql similarity index 100% rename from persist/src/main/resources/db/migration/hsql/18.0.8/V18.0.8.20241230.2__set_proper_pathway_and_compartment.sql rename to persist/src/main/resources/db/migration/hsql/18.1.0/V18.0.8.20241230.2__set_proper_pathway_and_compartment.sql diff --git a/persist/src/main/resources/db/migration/hsql/18.0.8/V18.0.8.20241230__add_pathway_to_element.sql b/persist/src/main/resources/db/migration/hsql/18.1.0/V18.0.8.20241230__add_pathway_to_element.sql similarity index 100% rename from persist/src/main/resources/db/migration/hsql/18.0.8/V18.0.8.20241230__add_pathway_to_element.sql rename to persist/src/main/resources/db/migration/hsql/18.1.0/V18.0.8.20241230__add_pathway_to_element.sql diff --git a/persist/src/main/resources/db/migration/hsql/18.0.8/V18.0.8.20250110__set_proper_pathway_and_compartment.sql b/persist/src/main/resources/db/migration/hsql/18.1.0/V18.0.8.20250110__set_proper_pathway_and_compartment.sql similarity index 100% rename from persist/src/main/resources/db/migration/hsql/18.0.8/V18.0.8.20250110__set_proper_pathway_and_compartment.sql rename to persist/src/main/resources/db/migration/hsql/18.1.0/V18.0.8.20250110__set_proper_pathway_and_compartment.sql diff --git a/persist/src/main/resources/db/migration/hsql/18.1.0/V18.1.0.20250122__add_immediate_link.sql b/persist/src/main/resources/db/migration/hsql/18.1.0/V18.1.0.20250122__add_immediate_link.sql new file mode 100644 index 0000000000000000000000000000000000000000..0e3d63ad1584a5f34dd777ed9e0411ff9569c7de --- /dev/null +++ b/persist/src/main/resources/db/migration/hsql/18.1.0/V18.1.0.20250122__add_immediate_link.sql @@ -0,0 +1,2 @@ +alter table element_table + add column immediate_link character varying(1024); diff --git a/persist/src/main/resources/db/migration/postgres/18.0.8/V18.0.8.20241213__remove_refresh_jobs.sql b/persist/src/main/resources/db/migration/postgres/18.1.0/V18.0.8.20241213__remove_refresh_jobs.sql similarity index 100% rename from persist/src/main/resources/db/migration/postgres/18.0.8/V18.0.8.20241213__remove_refresh_jobs.sql rename to persist/src/main/resources/db/migration/postgres/18.1.0/V18.0.8.20241213__remove_refresh_jobs.sql diff --git a/persist/src/main/resources/db/migration/postgres/18.0.8/V18.0.8.20241230.2__set_proper_pathway_and_compartment.sql b/persist/src/main/resources/db/migration/postgres/18.1.0/V18.0.8.20241230.2__set_proper_pathway_and_compartment.sql similarity index 100% rename from persist/src/main/resources/db/migration/postgres/18.0.8/V18.0.8.20241230.2__set_proper_pathway_and_compartment.sql rename to persist/src/main/resources/db/migration/postgres/18.1.0/V18.0.8.20241230.2__set_proper_pathway_and_compartment.sql diff --git a/persist/src/main/resources/db/migration/postgres/18.0.8/V18.0.8.20241230__add_pathway_to_element.sql b/persist/src/main/resources/db/migration/postgres/18.1.0/V18.0.8.20241230__add_pathway_to_element.sql similarity index 100% rename from persist/src/main/resources/db/migration/postgres/18.0.8/V18.0.8.20241230__add_pathway_to_element.sql rename to persist/src/main/resources/db/migration/postgres/18.1.0/V18.0.8.20241230__add_pathway_to_element.sql diff --git a/persist/src/main/resources/db/migration/postgres/18.0.8/V18.0.8.20250110__set_proper_pathway_and_compartment.sql b/persist/src/main/resources/db/migration/postgres/18.1.0/V18.0.8.20250110__set_proper_pathway_and_compartment.sql similarity index 100% rename from persist/src/main/resources/db/migration/postgres/18.0.8/V18.0.8.20250110__set_proper_pathway_and_compartment.sql rename to persist/src/main/resources/db/migration/postgres/18.1.0/V18.0.8.20250110__set_proper_pathway_and_compartment.sql diff --git a/persist/src/main/resources/db/migration/postgres/18.1.0/V18.1.0.20250122__add_immediate_link.sql b/persist/src/main/resources/db/migration/postgres/18.1.0/V18.1.0.20250122__add_immediate_link.sql new file mode 100644 index 0000000000000000000000000000000000000000..0e3d63ad1584a5f34dd777ed9e0411ff9569c7de --- /dev/null +++ b/persist/src/main/resources/db/migration/postgres/18.1.0/V18.1.0.20250122__add_immediate_link.sql @@ -0,0 +1,2 @@ +alter table element_table + add column immediate_link character varying(1024); diff --git a/pom.xml b/pom.xml index a791e54e985f0bd4e321f612cea65907ce21102b..60799bd1b535b763eb2c753bb0f8d60de59a4afc 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ <groupId>lcsb.mapviewer</groupId> <artifactId>parent</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> <packaging>pom</packaging> <name>parent MapViewer</name> diff --git a/rest-api/pom.xml b/rest-api/pom.xml index 2754569a70e17568408aa826e99df2a00ab08c01..35dfb9cb44e0d0fb73e264514a0054c9f097d2b4 100644 --- a/rest-api/pom.xml +++ b/rest-api/pom.xml @@ -7,7 +7,7 @@ <parent> <groupId>lcsb.mapviewer</groupId> <artifactId>parent</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </parent> <artifactId>rest-api</artifactId> <name>rest-api</name> @@ -19,19 +19,19 @@ <dependency> <groupId>lcsb.mapviewer</groupId> <artifactId>model</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </dependency> <dependency> <groupId>lcsb.mapviewer</groupId> <artifactId>service</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </dependency> <dependency> <groupId>lcsb.mapviewer</groupId> <artifactId>pathvisio</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </dependency> <dependency> diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/bioentities/elements/ElementsController.java b/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/bioentities/elements/ElementsController.java index fd7befb8ed9ad0ba1b0b9228737b580ff2ee06c3..a7df4e02c53485fcb641729d271459f81df82006 100644 --- a/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/bioentities/elements/ElementsController.java +++ b/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/bioentities/elements/ElementsController.java @@ -1,23 +1,5 @@ package lcsb.mapviewer.api.projects.models.bioentities.elements; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.MediaType; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.PathVariable; -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.QueryException; import lcsb.mapviewer.common.exception.InvalidArgumentException; @@ -49,6 +31,23 @@ import lcsb.mapviewer.persist.dao.map.species.ElementProperty; import lcsb.mapviewer.services.ObjectNotFoundException; import lcsb.mapviewer.services.interfaces.IElementService; import lcsb.mapviewer.services.interfaces.IModelService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.PathVariable; +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 java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; @RestController @RequestMapping( @@ -58,8 +57,8 @@ import lcsb.mapviewer.services.interfaces.IModelService; produces = MediaType.APPLICATION_JSON_VALUE) public class ElementsController extends BaseController { - private IElementService elementService; - private IModelService modelService; + private final IElementService elementService; + private final IModelService modelService; @Autowired public ElementsController(final IElementService elementService, final IModelService modelService) { @@ -68,7 +67,7 @@ public class ElementsController extends BaseController { } @PreAuthorize("hasAnyAuthority('IS_ADMIN', 'READ_PROJECT:' + #projectId)") - @RequestMapping(value = "/", method = { RequestMethod.GET, RequestMethod.POST }) + @RequestMapping(value = "/", method = {RequestMethod.GET, RequestMethod.POST}) public List<Map<String, Object>> getElements( final @PathVariable(value = "projectId") String projectId, final @PathVariable(value = "modelId") String modelId, @@ -183,6 +182,9 @@ public class ElementsController extends BaseController { value = ((Species) element).isBoundaryCondition(); } break; + case "immediatelink": + value = element.getImmediateLink(); + break; case "constant": if (element instanceof Species) { value = ((Species) element).isConstant(); @@ -389,6 +391,7 @@ public class ElementsController extends BaseController { result.add("other"); result.add("initialConcentration"); result.add("boundaryCondition"); + result.add("immediateLink"); result.add("constant"); result.add("hypothetical"); result.add("activity"); diff --git a/service/pom.xml b/service/pom.xml index 3b7309a0d02d1b6f1a48ecb782b211eb2f59e46e..624ca59f523a1215cadee2828f0694ed40ef3423 100644 --- a/service/pom.xml +++ b/service/pom.xml @@ -6,7 +6,7 @@ <parent> <groupId>lcsb.mapviewer</groupId> <artifactId>parent</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </parent> <artifactId>service</artifactId> @@ -19,7 +19,7 @@ <dependency> <groupId>lcsb.mapviewer</groupId> <artifactId>model</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </dependency> <!-- dependency from the MapViewer dao --> @@ -27,47 +27,47 @@ <dependency> <groupId>lcsb.mapviewer</groupId> <artifactId>persist</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </dependency> <dependency> <groupId>lcsb.mapviewer</groupId> <artifactId>model-command</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </dependency> <dependency> <groupId>lcsb.mapviewer</groupId> <artifactId>annotation</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </dependency> <!-- dependency from the MapViewer cell designer parser --> <dependency> <groupId>lcsb.mapviewer</groupId> <artifactId>converter-CellDesigner</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </dependency> <!-- dependency from the MapViewer SBGN-ML parser --> <dependency> <groupId>lcsb.mapviewer</groupId> <artifactId>converter-SBGNML</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </dependency> <!-- dependency from the MapViewer graphics converter --> <dependency> <groupId>lcsb.mapviewer</groupId> <artifactId>converter-graphics</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </dependency> <!-- dependency from the SBML parser --> <dependency> <groupId>lcsb.mapviewer</groupId> <artifactId>converter-sbml</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </dependency> <!-- Log4J2 --> diff --git a/web/pom.xml b/web/pom.xml index 6f85acdefcfbc021ce9f1020fe8f3d8dfaf40a04..503ad0060d576cf033c06312e0b8072bbf92179c 100644 --- a/web/pom.xml +++ b/web/pom.xml @@ -6,7 +6,7 @@ <parent> <groupId>lcsb.mapviewer</groupId> <artifactId>parent</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </parent> <artifactId>web</artifactId> <packaging>jar</packaging> @@ -36,19 +36,19 @@ <dependency> <groupId>lcsb.mapviewer</groupId> <artifactId>service</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </dependency> <dependency> <groupId>lcsb.mapviewer</groupId> <artifactId>rest-api</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </dependency> <dependency> <groupId>lcsb.mapviewer</groupId> <artifactId>frontend-js</artifactId> - <version>18.0.8</version> + <version>18.1.0</version> </dependency> <dependency> diff --git a/web/src/test/java/lcsb/mapviewer/web/MapControllerIntegrationTest.java b/web/src/test/java/lcsb/mapviewer/web/MapControllerIntegrationTest.java index bb6f173dce3245cdd6fe3e0997718380a1426013..ae2b7b6c7a0f8bd4864a2b12b152e7cb36842366 100644 --- a/web/src/test/java/lcsb/mapviewer/web/MapControllerIntegrationTest.java +++ b/web/src/test/java/lcsb/mapviewer/web/MapControllerIntegrationTest.java @@ -1,51 +1,7 @@ package lcsb.mapviewer.web; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; -import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; -import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.patch; -import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; -import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; -import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; -import static org.springframework.restdocs.payload.PayloadDocumentation.subsectionWithPath; -import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; -import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; -import static org.springframework.restdocs.request.RequestDocumentation.requestParameters; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.commons.lang3.StringUtils; -import org.apache.http.client.entity.UrlEncodedFormEntity; -import org.apache.http.message.BasicNameValuePair; -import org.apache.http.util.EntityUtils; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.MediaType; -import org.springframework.mock.web.MockHttpSession; -import org.springframework.restdocs.payload.FieldDescriptor; -import org.springframework.restdocs.payload.JsonFieldType; -import org.springframework.restdocs.payload.ResponseFieldsSnippet; -import org.springframework.restdocs.request.PathParametersSnippet; -import org.springframework.restdocs.request.RequestParametersSnippet; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.web.servlet.MvcResult; -import org.springframework.test.web.servlet.RequestBuilder; - import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; - import lcsb.mapviewer.api.projects.models.bioentities.elements.ElementsController; import lcsb.mapviewer.api.projects.models.bioentities.reactions.ReactionsController; import lcsb.mapviewer.common.Configuration; @@ -66,6 +22,49 @@ import lcsb.mapviewer.modelutils.map.ElementUtils; import lcsb.mapviewer.modelutils.serializer.model.map.ElementIdentifierType; import lcsb.mapviewer.services.interfaces.IModelService; import lcsb.mapviewer.services.interfaces.IUserService; +import org.apache.commons.lang3.StringUtils; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.util.EntityUtils; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.mock.web.MockHttpSession; +import org.springframework.restdocs.payload.FieldDescriptor; +import org.springframework.restdocs.payload.JsonFieldType; +import org.springframework.restdocs.payload.ResponseFieldsSnippet; +import org.springframework.restdocs.request.PathParametersSnippet; +import org.springframework.restdocs.request.RequestParametersSnippet; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.RequestBuilder; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.patch; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.restdocs.payload.PayloadDocumentation.subsectionWithPath; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; +import static org.springframework.restdocs.request.RequestDocumentation.requestParameters; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @RunWith(SpringJUnit4ClassRunner.class) public class MapControllerIntegrationTest extends ControllerIntegrationTest { @@ -116,6 +115,10 @@ public class MapControllerIntegrationTest extends ControllerIntegrationTest { .description("name") .type("string") .optional(), + fieldWithPath("[].immediateLink") + .description("link that should be opened immediately when element is clicked on the map") + .type(JsonFieldType.STRING) + .optional(), fieldWithPath("[].modelId") .description("map identifier") .type("number") @@ -514,7 +517,7 @@ public class MapControllerIntegrationTest extends ControllerIntegrationTest { RequestBuilder request = get("/minerva/api/projects/*/models/{mapId}/bioEntities:search?coordinates=104.36,182.81", map.getId()) - .session(session); + .session(session); mockMvc.perform(request) .andExpect(status().isNotFound()); @@ -810,7 +813,7 @@ public class MapControllerIntegrationTest extends ControllerIntegrationTest { RequestBuilder request = get("/minerva/api/projects/{projectId}/models/{mapId}:downloadImage?" + "handlerClass=" + PngImageGenerator.class.getCanonicalName(), TEST_PROJECT, map.getId()) - .session(session); + .session(session); mockMvc.perform(request) .andDo(document("projects/project_maps/download_image_simple", @@ -860,11 +863,11 @@ public class MapControllerIntegrationTest extends ControllerIntegrationTest { DataOverlay overlay = createOverlay(project, admin, "name\tvalue\nGSTA4\t1"); RequestBuilder request = get("/minerva/api/projects/{projectId}/models/{mapId}:downloadModel?" - + "handlerClass={handlerClass}" - + "&overlayIds={overlayId}", TEST_PROJECT, submap.getId(), + + "handlerClass={handlerClass}" + + "&overlayIds={overlayId}", TEST_PROJECT, submap.getId(), CellDesignerXmlParser.class.getCanonicalName(), overlay.getId()) - .session(session); + .session(session); mockMvc.perform(request) .andExpect(status().is2xxSuccessful()); @@ -874,7 +877,7 @@ public class MapControllerIntegrationTest extends ControllerIntegrationTest { public void testDownloadSubmapModelWithPost() throws Exception { ModelData submap = getSubmap(); - String body = EntityUtils.toString(new UrlEncodedFormEntity(Arrays.asList( + String body = EntityUtils.toString(new UrlEncodedFormEntity(Collections.singletonList( new BasicNameValuePair("handlerClass", CellDesignerXmlParser.class.getCanonicalName())))); RequestBuilder request = get("/minerva/api/projects/{projectId}/models/{mapId}:downloadModel", TEST_PROJECT, submap.getId()) @@ -893,12 +896,12 @@ public class MapControllerIntegrationTest extends ControllerIntegrationTest { userService.getUserByLogin(BUILT_IN_TEST_ADMIN_LOGIN)); RequestBuilder request = get("/minerva/api/projects/{projectId}/models/{mapId}:downloadImage?" - + "handlerClass={handlerClass}&overlayIds={ids}", + + "handlerClass={handlerClass}&overlayIds={ids}", TEST_PROJECT, map.getId(), PngImageGenerator.class.getCanonicalName(), overlay.getId()) - .session(session); + .session(session); mockMvc.perform(request) .andDo(document("projects/project_maps/download_image_data_overlay", @@ -913,14 +916,14 @@ public class MapControllerIntegrationTest extends ControllerIntegrationTest { RequestBuilder elementRequest = get("/minerva/api/projects/{projectId}/models/*/bioEntities/elements/", TEST_PROJECT) - .session(session); + .session(session); String content = mockMvc.perform(elementRequest).andReturn().getResponse().getContentAsString(); RequestBuilder request = get("/minerva/api/projects/{projectId}/models/{mapId}:downloadImage?" - + "handlerClass=" + PdfImageGenerator.class.getCanonicalName() - + "&polygonString=10000,10000;10001,10000;10000,10001", + + "handlerClass=" + PdfImageGenerator.class.getCanonicalName() + + "&polygonString=10000,10000;10001,10000;10000,10001", TEST_PROJECT, map.getId()) - .session(session); + .session(session); mockMvc.perform(request) .andExpect(status().is2xxSuccessful()); @@ -946,7 +949,7 @@ public class MapControllerIntegrationTest extends ControllerIntegrationTest { RequestBuilder request = get("/minerva/api/projects/{projectId}/models/{mapId}:downloadImage?" + "handlerClass=" + PdfImageGenerator.class.getCanonicalName() + "&polygonString=0,0;100,0;100,100;0,100", TEST_PROJECT, map.getId()) - .session(session); + .session(session); mockMvc.perform(request) .andDo(document("projects/project_maps/download_image_polygon", @@ -978,8 +981,8 @@ public class MapControllerIntegrationTest extends ControllerIntegrationTest { RequestBuilder request = get("/minerva/api/projects/*/models/" + map.getId() + ":downloadImage?" + "handlerClass=" + PngImageGenerator.class.getCanonicalName()) - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .session(session); + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .session(session); mockMvc.perform(request) .andExpect(status().isNotFound()); @@ -992,7 +995,7 @@ public class MapControllerIntegrationTest extends ControllerIntegrationTest { RequestBuilder request = get( "/minerva/api/projects/" + TEST_PROJECT + "/models/" + map.getId() + ":downloadModelWarnings?" + "handlerClass=" + SbgnmlXmlConverter.class.getCanonicalName()) - .session(session); + .session(session); String response = mockMvc.perform(request) .andExpect(status().is2xxSuccessful()) @@ -1002,7 +1005,7 @@ public class MapControllerIntegrationTest extends ControllerIntegrationTest { }); int elements = ((List<?>) result.get("data")).size(); - assertTrue(elements == 0); + assertEquals(0, elements); } @Test @@ -1011,8 +1014,8 @@ public class MapControllerIntegrationTest extends ControllerIntegrationTest { RequestBuilder request = get("/minerva/api/projects/" + TEST_PROJECT + "/models/" + map.getId() + ":downloadModel?" + "handlerClass=" + CellDesignerXmlParser.class.getCanonicalName()) - .accept(MimeType.ZIP.getTextRepresentation() + ";q=0.8") - .session(session); + .accept(MimeType.ZIP.getTextRepresentation() + ";q=0.8") + .session(session); MvcResult result = mockMvc.perform(request) .andExpect(status().is2xxSuccessful()) @@ -1027,8 +1030,8 @@ public class MapControllerIntegrationTest extends ControllerIntegrationTest { RequestBuilder request = get("/minerva/api/projects/*/models/" + map.getId() + ":downloadModel?" + "handlerClass=" + CellDesignerXmlParser.class.getCanonicalName()) - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .session(session); + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .session(session); mockMvc.perform(request) .andExpect(status().isNotFound()); diff --git a/web/src/test/java/lcsb/mapviewer/web/api/NewApiDocs.java b/web/src/test/java/lcsb/mapviewer/web/api/NewApiDocs.java index 62ad21b1637c23c0a76ceb99b37f52ae8350a251..13293284c354ec1fc344b6bc9ffeb45cc6b82ea9 100644 --- a/web/src/test/java/lcsb/mapviewer/web/api/NewApiDocs.java +++ b/web/src/test/java/lcsb/mapviewer/web/api/NewApiDocs.java @@ -232,12 +232,16 @@ public class NewApiDocs { private List<FieldDescriptor> getBioEntitySpecificFields(final String prefix) { final List<FieldDescriptor> result = new ArrayList<>(); + result.add( + fieldWithPath(prefix + "immediateLink") + .description("link that should be opened immediately when element is clicked on the map") + .optional() + .type(JsonFieldType.STRING)); result.add( fieldWithPath(prefix + "id") .description("unique bioEntity identifier") .type(JsonFieldType.NUMBER)); result.add( - fieldWithPath(prefix + "stringType") .description("type of the bioEntity") .type(JsonFieldType.STRING));