Commit 99cf1a24 authored by Piotr Gawron's avatar Piotr Gawron
Browse files

invalid SBML crashed jsbml

parent e40d25d3
Pipeline #50697 failed with stage
in 60 minutes and 2 seconds
......@@ -4,6 +4,7 @@ minerva (16.0.5) stable; urgency=medium
* Bug fix (performance): fetching all bioEntities using JS API was time
consuming (#1605)
* Bug fix (performance): showing data overlay on big map was time consuming
* Bug fix: invalid SBML file could crash map upload/format conversion (#1611)
-- Piotr Gawron <piotr.gawron@uni.lu> Mon, 13 Dec 2021 15:00:00 +0200
......
package lcsb.mapviewer.converter.model.sbml;
import java.util.*;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import javax.xml.stream.XMLStreamException;
......@@ -19,7 +21,11 @@ import lcsb.mapviewer.commands.CommandExecutionException;
import lcsb.mapviewer.commands.layout.ApplySimpleLayoutModelCommand;
import lcsb.mapviewer.common.Configuration;
import lcsb.mapviewer.common.MimeType;
import lcsb.mapviewer.converter.*;
import lcsb.mapviewer.converter.Converter;
import lcsb.mapviewer.converter.ConverterException;
import lcsb.mapviewer.converter.ConverterParams;
import lcsb.mapviewer.converter.InvalidInputDataExecption;
import lcsb.mapviewer.converter.ZIndexPopulator;
import lcsb.mapviewer.converter.model.sbml.compartment.SbmlCompartmentParser;
import lcsb.mapviewer.converter.model.sbml.reaction.SbmlReactionParser;
import lcsb.mapviewer.converter.model.sbml.species.SbmlSpeciesParser;
......@@ -29,8 +35,12 @@ import lcsb.mapviewer.model.map.InconsistentModelException;
import lcsb.mapviewer.model.map.model.Model;
import lcsb.mapviewer.model.map.model.ModelFullIndexed;
import lcsb.mapviewer.model.map.modifier.Modulation;
import lcsb.mapviewer.model.map.reaction.*;
import lcsb.mapviewer.model.map.species.*;
import lcsb.mapviewer.model.map.reaction.AbstractNode;
import lcsb.mapviewer.model.map.reaction.Modifier;
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 lcsb.mapviewer.model.map.species.field.ModificationResidue;
import lcsb.mapviewer.model.map.species.field.SpeciesWithModificationResidue;
......@@ -45,86 +55,89 @@ public class SbmlParser extends Converter {
boolean provideDefaults = true;
@Override
public Model createModel(ConverterParams params) throws InvalidInputDataExecption {
try {
Model model = new ModelFullIndexed(null);
public Model createModel(final ConverterParams params) throws InvalidInputDataExecption {
Model model = new ModelFullIndexed(null);
if (params.getFilename() != null) {
model.setName(FilenameUtils.getBaseName(params.getFilename()));
}
SBMLDocument sbmlDocument = SBMLReader.read(params.getInputStream());
org.sbml.jsbml.Model sbmlModel = sbmlDocument.getModel();
model.setIdModel(sbmlModel.getId());
if (model.getIdModel() != null && model.getIdModel().isEmpty()) {
model.setIdModel(null);
}
model.setName(sbmlModel.getName());
model.setNotes(NotesUtility.extractNotes(sbmlModel));
checkAvailableExtensions(sbmlModel);
Layout layout = getSbmlLayout(sbmlModel);
boolean layoutExists = layout != null;
SbmlCompartmentParser compartmentParser = new SbmlCompartmentParser(sbmlModel, model);
SbmlSpeciesParser speciesParser = new SbmlSpeciesParser(sbmlModel, model);
SbmlReactionParser reactionParser = new SbmlReactionParser(sbmlModel, model, speciesParser, compartmentParser);
SbmlUnitsParser unitParser = new SbmlUnitsParser(sbmlModel, model);
SbmlParameterParser parameterParser = new SbmlParameterParser(sbmlModel, model);
SbmlFunctionParser functionParser = new SbmlFunctionParser(sbmlModel, model);
model.addMiriamData(compartmentParser.extractMiriamDataFromAnnotation(sbmlModel.getAnnotation(), null));
model.addAuthors(compartmentParser.extractAuthorsFromAnnotation(sbmlModel.getAnnotation()));
model.addModificationDates(compartmentParser.extractModificationDatesFromAnnotation(sbmlModel.getAnnotation()));
model.setCreationDate(compartmentParser.extractCreationDateFromAnnotation(sbmlModel.getAnnotation()));
model.addUnits(unitParser.parseList(sbmlModel));
model.addParameters(parameterParser.parseList(sbmlModel));
model.addFunctions(functionParser.parseList(sbmlModel));
model.addElements(compartmentParser.parseList());
model.addElements(speciesParser.parseList());
model.addReactions(reactionParser.parseList());
if (layoutExists) {
if (layout.getDimensions() != null) {
model.setWidth(layout.getDimensions().getWidth());
model.setHeight(layout.getDimensions().getHeight());
if (params.getFilename() != null) {
model.setName(FilenameUtils.getBaseName(params.getFilename()));
}
SBMLDocument sbmlDocument = null;
try {
sbmlDocument = SBMLReader.read(params.getInputStream());
} catch (XMLStreamException e) {
throw new InvalidInputDataExecption(e);
} catch (Exception e) {
throw new InvalidInputDataExecption("JSbml library could not parse provided input.\n" + e.getMessage(), e);
}
org.sbml.jsbml.Model sbmlModel = sbmlDocument.getModel();
model.setIdModel(sbmlModel.getId());
if (model.getIdModel() != null && model.getIdModel().isEmpty()) {
model.setIdModel(null);
}
model.setName(sbmlModel.getName());
model.setNotes(NotesUtility.extractNotes(sbmlModel));
checkAvailableExtensions(sbmlModel);
Layout layout = getSbmlLayout(sbmlModel);
boolean layoutExists = layout != null;
SbmlCompartmentParser compartmentParser = new SbmlCompartmentParser(sbmlModel, model);
SbmlSpeciesParser speciesParser = new SbmlSpeciesParser(sbmlModel, model);
SbmlReactionParser reactionParser = new SbmlReactionParser(sbmlModel, model, speciesParser, compartmentParser);
SbmlUnitsParser unitParser = new SbmlUnitsParser(sbmlModel, model);
SbmlParameterParser parameterParser = new SbmlParameterParser(sbmlModel, model);
SbmlFunctionParser functionParser = new SbmlFunctionParser(sbmlModel, model);
model.addMiriamData(compartmentParser.extractMiriamDataFromAnnotation(sbmlModel.getAnnotation(), null));
model.addAuthors(compartmentParser.extractAuthorsFromAnnotation(sbmlModel.getAnnotation()));
model.addModificationDates(compartmentParser.extractModificationDatesFromAnnotation(sbmlModel.getAnnotation()));
model.setCreationDate(compartmentParser.extractCreationDateFromAnnotation(sbmlModel.getAnnotation()));
model.addUnits(unitParser.parseList(sbmlModel));
model.addParameters(parameterParser.parseList(sbmlModel));
model.addFunctions(functionParser.parseList(sbmlModel));
model.addElements(compartmentParser.parseList());
model.addElements(speciesParser.parseList());
model.addReactions(reactionParser.parseList());
if (layoutExists) {
if (layout.getDimensions() != null) {
model.setWidth(layout.getDimensions().getWidth());
model.setHeight(layout.getDimensions().getHeight());
}
compartmentParser.mergeLayout(model.getCompartments());
speciesParser.mergeLayout(model.getSpeciesList());
reactionParser.mergeLayout(model.getReactions());
}
compartmentParser.mergeLayout(model.getCompartments());
speciesParser.mergeLayout(model.getSpeciesList());
reactionParser.mergeLayout(model.getReactions());
}
reactionParser.validateReactions(model.getReactions());
reactionParser.validateReactions(model.getReactions());
if (sbmlModel.getConstraintCount() > 0) {
logger.warn("Constraints not implemented for model");
}
if (sbmlModel.getConversionFactorInstance() != null) {
logger.warn("ConversionFactor not implemented for model");
}
if (sbmlModel.getEventCount() > 0 || sbmlModel.getEventAssignmentCount() > 0) {
logger.warn("Handling of Events is not implemented for model");
}
if (sbmlModel.getInitialAssignmentCount() > 0) {
logger.warn("InitialAssignment not implemented for model");
}
if (sbmlModel.getRuleCount() > 0) {
logger.warn("Rule not implemented for model");
}
if (layoutExists) {
addComplexRelationsBasedOnCoordinates(model);
}
createLayout(model, layout, params.isSizeAutoAdjust(), reactionParser);
return model;
} catch (XMLStreamException e) {
throw new InvalidInputDataExecption(e);
if (sbmlModel.getConstraintCount() > 0) {
logger.warn("Constraints not implemented for model");
}
if (sbmlModel.getConversionFactorInstance() != null) {
logger.warn("ConversionFactor not implemented for model");
}
if (sbmlModel.getEventCount() > 0 || sbmlModel.getEventAssignmentCount() > 0) {
logger.warn("Handling of Events is not implemented for model");
}
if (sbmlModel.getInitialAssignmentCount() > 0) {
logger.warn("InitialAssignment not implemented for model");
}
if (sbmlModel.getRuleCount() > 0) {
logger.warn("Rule not implemented for model");
}
if (layoutExists) {
addComplexRelationsBasedOnCoordinates(model);
}
createLayout(model, layout, params.isSizeAutoAdjust(), reactionParser);
return model;
}
@Override
public String model2String(Model model) throws ConverterException {
public String model2String(final Model model) throws ConverterException {
try {
SbmlExporter sbmlExporter = new SbmlExporter();
sbmlExporter.setProvideDefaults(provideDefaults);
......@@ -149,7 +162,7 @@ public class SbmlParser extends Converter {
return "xml";
}
private void addComplexRelationsBasedOnCoordinates(Model model) {
private void addComplexRelationsBasedOnCoordinates(final Model model) {
for (Element element : model.getElements()) {
if (element instanceof Species) {
Species species = (Species) element;
......@@ -163,7 +176,7 @@ public class SbmlParser extends Converter {
}
}
private Complex findComplexForElement(Species species, Model model) {
private Complex findComplexForElement(final Species species, final Model model) {
Complex result = null;
for (Element element : model.getElements()) {
if (element instanceof Complex && element != species) {
......@@ -182,7 +195,7 @@ public class SbmlParser extends Converter {
return result;
}
private void createLayout(Model model, Layout layout, boolean resize, SbmlReactionParser parser)
private void createLayout(final Model model, final Layout layout, final boolean resize, final SbmlReactionParser parser)
throws InvalidInputDataExecption {
if (model.getWidth() <= Configuration.EPSILON) {
double maxY = 1;
......@@ -225,7 +238,7 @@ public class SbmlParser extends Converter {
new ZIndexPopulator().populateZIndex(model);
}
private void updateModifierTypes(Reaction reaction) {
private void updateModifierTypes(final Reaction reaction) {
Set<Modifier> modifiersToBeRemoved = new HashSet<>();
Set<Modifier> modifiersToBeAdded = new HashSet<>();
for (Modifier modifier : reaction.getModifiers()) {
......@@ -242,7 +255,7 @@ public class SbmlParser extends Converter {
}
}
private boolean hasLayout(Reaction reaction) {
private boolean hasLayout(final Reaction reaction) {
for (AbstractNode node : reaction.getNodes()) {
if (node.getLine() == null) {
return false;
......@@ -254,7 +267,7 @@ public class SbmlParser extends Converter {
return true;
}
private Layout getSbmlLayout(org.sbml.jsbml.Model sbmlModel) {
private Layout getSbmlLayout(final org.sbml.jsbml.Model sbmlModel) {
Layout layout = null;
if (sbmlModel.getExtensionCount() > 0) {
......@@ -275,7 +288,7 @@ public class SbmlParser extends Converter {
return layout;
}
private void checkAvailableExtensions(org.sbml.jsbml.Model sbmlModel) {
private void checkAvailableExtensions(final org.sbml.jsbml.Model sbmlModel) {
if (sbmlModel.getExtensionCount() > 0) {
for (SBasePlugin plugin : sbmlModel.getExtensionPackages().values()) {
if (!plugin.getClass().equals(LayoutModelPlugin.class) &&
......@@ -286,7 +299,7 @@ public class SbmlParser extends Converter {
}
}
public void setProvideDefaults(boolean b) {
public void setProvideDefaults(final boolean b) {
this.provideDefaults = b;
}
......
package lcsb.mapviewer.converter.model.sbml;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.FileNotFoundException;
import java.util.HashSet;
......@@ -12,12 +15,19 @@ import org.junit.Test;
import lcsb.mapviewer.commands.CreateHierarchyCommand;
import lcsb.mapviewer.common.Configuration;
import lcsb.mapviewer.converter.*;
import lcsb.mapviewer.converter.ConverterException;
import lcsb.mapviewer.converter.ConverterParams;
import lcsb.mapviewer.converter.InvalidInputDataExecption;
import lcsb.mapviewer.converter.model.celldesigner.CellDesignerXmlParser;
import lcsb.mapviewer.model.map.compartment.Compartment;
import lcsb.mapviewer.model.map.model.Model;
import lcsb.mapviewer.model.map.reaction.*;
import lcsb.mapviewer.model.map.species.*;
import lcsb.mapviewer.model.map.reaction.Reactant;
import lcsb.mapviewer.model.map.reaction.Reaction;
import lcsb.mapviewer.model.map.reaction.ReactionNode;
import lcsb.mapviewer.model.map.species.Element;
import lcsb.mapviewer.model.map.species.Gene;
import lcsb.mapviewer.model.map.species.GenericProtein;
import lcsb.mapviewer.model.map.species.Species;
public class SbmlParserTest extends SbmlTestFunctions {
Logger logger = LogManager.getLogger();
......@@ -282,4 +292,9 @@ public class SbmlParserTest extends SbmlTestFunctions {
assertNotNull(reaction.getProcessCoordinates());
}
@Test(expected = InvalidInputDataExecption.class)
public void testParseProblematicFile() throws FileNotFoundException, InvalidInputDataExecption {
parser.createModel(new ConverterParams().filename("testFiles/problem_in_sbml.xml"));
}
}
<?xml version="1.0" encoding="UTF-8"?>
<compartment id="comp_0" name="compartment1"
constant="false" />
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment