diff --git a/CHANGELOG b/CHANGELOG index 68e8a13aaa71072819a31384b88aaa35076a293c..8c14990d688290edf73c98af49f4085c20650892 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,9 @@ +minerva (14.0.3) stable; urgency=medium + * Bug fix: parsing of CellDesigner files that contained substanceUnits could + crash the upload (#985) + + -- Piotr Gawron <piotr.gawron@uni.lu> Wed, 16 Oct 2019 9:00:00 +0200 + minerva (14.0.2) stable; urgency=medium * Bug fix: Genetic data overlay uploaded prior to 14.0.0 crashed maps (#988) 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 37084d1bd0d9dd30292a8ded5c05ae0cb2a6c14b..c6386575d66324c51057c8837de764cddd3d11d8 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 @@ -98,7 +98,7 @@ public class CellDesignerXmlParser extends Converter { if (params.getFilename() != null) { model.setName(FilenameUtils.getBaseName(params.getFilename())); } - speciesSbmlParser = new SpeciesCollectionXmlParser(elements); + speciesSbmlParser = new SpeciesCollectionXmlParser(elements, model.getUnits()); aliasCollectionParser = new AliasCollectionXmlParser(elements, model); compartmentCollectionXmlParser = new CompartmentCollectionXmlParser(elements); @@ -133,21 +133,6 @@ public class CellDesignerXmlParser extends Converter { model.setIdModel(modelId); } - Node compartmentNode = XmlParser.getNode("listOfCompartments", modelNode.getChildNodes()); - if (compartmentNode != null) { - List<CellDesignerCompartment> compartments = compartmentCollectionXmlParser - .parseXmlCompartmentCollection(compartmentNode); - elements.addElements(compartments); - } - - InternalModelSpeciesData modelData = new InternalModelSpeciesData(); - - Node speciesNode = XmlParser.getNode("listOfSpecies", modelNode.getChildNodes()); - if (speciesNode != null) { - List<Pair<String, ? extends CellDesignerSpecies<?>>> species = speciesSbmlParser - .parseSbmlSpeciesCollection(speciesNode); - modelData.updateSpecies(species); - } Node reactionsNode = null; Node functionsNode = null; Node unitsNode = null; @@ -192,6 +177,22 @@ public class CellDesignerXmlParser extends Converter { model.addParameters(parameterParser.parseXmlParameterCollection(parametersNode)); } + Node compartmentNode = XmlParser.getNode("listOfCompartments", modelNode.getChildNodes()); + if (compartmentNode != null) { + List<CellDesignerCompartment> compartments = compartmentCollectionXmlParser + .parseXmlCompartmentCollection(compartmentNode); + elements.addElements(compartments); + } + + InternalModelSpeciesData modelData = new InternalModelSpeciesData(); + + Node speciesNode = XmlParser.getNode("listOfSpecies", modelNode.getChildNodes()); + if (speciesNode != null) { + List<Pair<String, ? extends CellDesignerSpecies<?>>> species = speciesSbmlParser + .parseSbmlSpeciesCollection(speciesNode); + modelData.updateSpecies(species); + } + Node annotationNode = XmlParser.getNode("annotation", modelNode.getChildNodes()); if (annotationNode == null) { throw new InvalidInputDataExecption("No annotation node in SBML/model"); @@ -388,7 +389,7 @@ public class CellDesignerXmlParser extends Converter { private void parseAnnotationExtension(Model model, InternalModelSpeciesData modelData, CellDesignerElementCollection elements, Node extensionNode) throws InvalidXmlSchemaException { - SpeciesCollectionXmlParser parser = new SpeciesCollectionXmlParser(elements); + SpeciesCollectionXmlParser parser = new SpeciesCollectionXmlParser(elements, model.getUnits()); NodeList nodes = extensionNode.getChildNodes(); Node includedSpecies = null; @@ -598,7 +599,7 @@ public class CellDesignerXmlParser extends Converter { try { CellDesignerElementCollection elements = new CellDesignerElementCollection(); - SpeciesCollectionXmlParser speciesCollectionXmlParser = new SpeciesCollectionXmlParser(elements); + SpeciesCollectionXmlParser speciesCollectionXmlParser = new SpeciesCollectionXmlParser(elements, model.getUnits()); ReactionCollectionXmlParser reactionCollectionXmlParser = new ReactionCollectionXmlParser(model, elements, false); UnitCollectionXmlParser unitCollectionXmlParser = new UnitCollectionXmlParser(); FunctionCollectionXmlParser functionCollectionXmlParser = new FunctionCollectionXmlParser(); @@ -667,7 +668,7 @@ public class CellDesignerXmlParser extends Converter { * @return annotation xml string for the model */ private String annotationToXml(Model model, CellDesignerElementCollection elements) { - SpeciesCollectionXmlParser speciesCollectionXmlParser = new SpeciesCollectionXmlParser(elements); + SpeciesCollectionXmlParser speciesCollectionXmlParser = new SpeciesCollectionXmlParser(elements, model.getUnits()); StringBuilder result = new StringBuilder(); result.append("<annotation>\n"); diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/species/SpeciesCollectionXmlParser.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/species/SpeciesCollectionXmlParser.java index c7647412b1a5c27f870c47feb3256546ab1951ab..d174992a69afced89e30ae83ef3814f0974395c3 100644 --- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/species/SpeciesCollectionXmlParser.java +++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/species/SpeciesCollectionXmlParser.java @@ -16,6 +16,7 @@ import lcsb.mapviewer.converter.model.celldesigner.CellDesignerElementCollection import lcsb.mapviewer.converter.model.celldesigner.annotation.RestAnnotationParser; import lcsb.mapviewer.converter.model.celldesigner.structure.*; import lcsb.mapviewer.model.map.InconsistentModelException; +import lcsb.mapviewer.model.map.kinetics.SbmlUnit; import lcsb.mapviewer.model.map.species.*; /** @@ -95,6 +96,8 @@ public class SpeciesCollectionXmlParser { */ private CellDesignerElementCollection elements; + private Collection<SbmlUnit> units; + /** * Default constructor. Model is required because some CellDesigner nodes * require access to other parts of the model. @@ -103,9 +106,10 @@ public class SpeciesCollectionXmlParser { * collection of {@link CellDesignerElement cell designer elements} * parsed from xml */ - public SpeciesCollectionXmlParser(CellDesignerElementCollection elements) { - sbmlSpeciesParser = new SpeciesSbmlParser(elements); + public SpeciesCollectionXmlParser(CellDesignerElementCollection elements, Collection<SbmlUnit> units) { + sbmlSpeciesParser = new SpeciesSbmlParser(elements, units); this.elements = elements; + this.units = units; rnaParser = new RnaXmlParser(elements); geneParser = new GeneXmlParser(elements); proteinParser = new ProteinXmlParser(elements); @@ -390,7 +394,7 @@ public class SpeciesCollectionXmlParser { // Probably this should be improved, this part of a CD model is really // messy. NodeList nodes = spieciesNode.getChildNodes(); - SpeciesSbmlParser parser = new SpeciesSbmlParser(elements); + SpeciesSbmlParser parser = new SpeciesSbmlParser(elements, units); for (int x = 0; x < nodes.getLength(); x++) { Node node = nodes.item(x); if (node.getNodeType() == Node.ELEMENT_NODE) { diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/species/SpeciesSbmlParser.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/species/SpeciesSbmlParser.java index de2bdea00a1d52d932cbb9681d8343286c23eb49..d6065ed852c48bd0504d41ec903e6ea63f5f722e 100644 --- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/species/SpeciesSbmlParser.java +++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/species/SpeciesSbmlParser.java @@ -1,5 +1,7 @@ package lcsb.mapviewer.converter.model.celldesigner.species; +import java.util.Collection; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.w3c.dom.Node; @@ -16,6 +18,7 @@ import lcsb.mapviewer.converter.model.celldesigner.structure.fields.CellDesigner import lcsb.mapviewer.converter.model.celldesigner.structure.fields.SpeciesState; import lcsb.mapviewer.model.map.compartment.Compartment; import lcsb.mapviewer.model.map.compartment.PathwayCompartment; +import lcsb.mapviewer.model.map.kinetics.SbmlUnit; import lcsb.mapviewer.model.map.kinetics.SbmlUnitType; import lcsb.mapviewer.model.map.model.ModelData; import lcsb.mapviewer.model.map.species.*; @@ -43,6 +46,8 @@ public class SpeciesSbmlParser extends AbstractElementXmlParser<CellDesignerSpec */ private CellDesignerElementCollection elements; + private Collection<SbmlUnit> units; + /** * Default constructor. Model is required because some nodes require access to * other parts of the model. @@ -51,8 +56,9 @@ public class SpeciesSbmlParser extends AbstractElementXmlParser<CellDesignerSpec * collection of {@link CellDesignerElement cell designer elements} * parsed from xml */ - public SpeciesSbmlParser(CellDesignerElementCollection elements) { + public SpeciesSbmlParser(CellDesignerElementCollection elements, Collection<SbmlUnit> units) { this.elements = elements; + this.units = units; } @Override @@ -146,7 +152,17 @@ public class SpeciesSbmlParser extends AbstractElementXmlParser<CellDesignerSpec species.setInitialAmount(XmlParser.getNodeAttr("initialAmount", spieciesNode)); String substanceUnits = XmlParser.getNodeAttr("substanceUnits", spieciesNode); if (substanceUnits != null && !substanceUnits.isEmpty()) { - species.setSubstanceUnits(SbmlUnitType.valueOf(substanceUnits.toUpperCase())); + SbmlUnit sbmlUnit = null; + for (SbmlUnit unit : units) { + if (unit.getUnitId().equals(substanceUnits)) { + sbmlUnit = unit; + } + } + if (sbmlUnit != null) { + species.setSubstanceUnits(sbmlUnit); + } else { + species.setSubstanceUnits(SbmlUnitType.valueOf(substanceUnits.toUpperCase())); + } } species.setInitialAmount(XmlParser.getNodeAttr("initialAmount", spieciesNode)); species.setInitialConcentration(XmlParser.getNodeAttr("initialConcentration", spieciesNode)); @@ -196,7 +212,11 @@ public class SpeciesSbmlParser extends AbstractElementXmlParser<CellDesignerSpec attributesBuilder.append(" hasOnlySubstanceUnits=\"" + species.hasOnlySubstanceUnits() + "\""); } if (species.getSubstanceUnits() != null) { - attributesBuilder.append(" substanceUnits=\"" + species.getSubstanceUnits().toString().toLowerCase() + "\""); + if (species.getSubstanceUnits() instanceof SbmlUnit) { + attributesBuilder.append(" substanceUnits=\"" + ((SbmlUnit)species.getSubstanceUnits()).getUnitId().toLowerCase() + "\""); + } else { + attributesBuilder.append(" substanceUnits=\"" + species.getSubstanceUnits().toString().toLowerCase() + "\""); + } } if (species.getConstant() != null) { attributesBuilder.append(" constant=\"" + species.getConstant().toString().toLowerCase() + "\""); diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerSpecies.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerSpecies.java index 2f162057b66c7d686bbcdad91d81842da1d07c15..35f6b92423cf3873fcc70fad6025929cd29a17e5 100644 --- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerSpecies.java +++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerSpecies.java @@ -6,6 +6,7 @@ import org.apache.logging.log4j.Logger; import lcsb.mapviewer.common.exception.InvalidArgumentException; import lcsb.mapviewer.common.exception.NotImplementedException; import lcsb.mapviewer.model.map.MiriamData; +import lcsb.mapviewer.model.map.kinetics.SbmlUnit; import lcsb.mapviewer.model.map.kinetics.SbmlUnitType; import lcsb.mapviewer.model.map.species.Species; import lcsb.mapviewer.model.map.species.field.PositionToCompartment; @@ -70,7 +71,20 @@ public class CellDesignerSpecies<T extends Species> extends CellDesignerElement< */ private Boolean hypothetical = null; - private SbmlUnitType substanceUnits; + /** + * SBML allows to store substanceUnit as either basic SI unit type or complex + * unit definition. To map it properly to database we need to separate the type + * into two properties. This property is responsible for basic SI unit type. + */ + private SbmlUnitType substanceUnitRawType; + + /** + * SBML allows to store substanceUnit as either basic SI unit type or complex + * unit definition. To map it properly to database we need to separate the type + * into two properties. This property is responsible for complex unit + * definition. + */ + private SbmlUnit substanceUnitComlexType; private Boolean boundaryCondition; @@ -93,7 +107,8 @@ public class CellDesignerSpecies<T extends Species> extends CellDesignerElement< this.onlySubstanceUnits = species.onlySubstanceUnits; this.homodimer = species.homodimer; this.constant = species.constant; - this.substanceUnits = species.substanceUnits; + this.substanceUnitComlexType = species.substanceUnitComlexType; + this.substanceUnitRawType = species.substanceUnitRawType; this.boundaryCondition = species.boundaryCondition; } @@ -287,7 +302,11 @@ public class CellDesignerSpecies<T extends Species> extends CellDesignerElement< if (boundaryCondition != null) { result.setBoundaryCondition(boundaryCondition); } - result.setSubstanceUnits(substanceUnits); + if (substanceUnitComlexType != null) { + result.setSubstanceUnits(substanceUnitComlexType); + } else { + result.setSubstanceUnits(substanceUnitRawType); + } result.setHomodimer(homodimer); result.setPositionToCompartment(positionToCompartment); result.setHypothetical(hypothetical); @@ -503,11 +522,21 @@ public class CellDesignerSpecies<T extends Species> extends CellDesignerElement< } public void setSubstanceUnits(SbmlUnitType substanceUnits) { - this.substanceUnits = substanceUnits; + this.substanceUnitRawType = substanceUnits; + } + + public void setSubstanceUnits(SbmlUnit substanceUnits) { + this.substanceUnitComlexType = substanceUnits; } - public SbmlUnitType getSubstanceUnit() { - return this.substanceUnits; + public Object getSubstanceUnit() { + if (substanceUnitComlexType != null) { + return substanceUnitComlexType; + } else if (substanceUnitRawType != null) { + return substanceUnitRawType; + } else { + return null; + } } public Boolean isBoundaryCondition() { diff --git a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/CellDesignerXmlParserTest.java b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/CellDesignerXmlParserTest.java index be028cc32e0977ae977f16aad1ebfd2acd24f4cc..021b121691d9aeefdfc3a58f64b02164a6d1e4b6 100644 --- a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/CellDesignerXmlParserTest.java +++ b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/CellDesignerXmlParserTest.java @@ -67,6 +67,16 @@ public class CellDesignerXmlParserTest extends CellDesignerTestFunctions { assertEquals("sample", model.getName()); } + @Test + public void testSubstanceUnitAsType() throws Exception { + CellDesignerXmlParser parser = new CellDesignerXmlParser(); + Model model = parser + .createModel(new ConverterParams().filename("testFiles/problematic/substance_defined_as_type.xml").sizeAutoAdjust(false)); + assertNotNull(model); + assertNotNull(model.getSpeciesList().get(0).getSubstanceUnits()); + super.testXmlSerialization(model); + } + @Test public void testParseTransparency() throws Exception { CellDesignerXmlParser parser = new CellDesignerXmlParser(); diff --git a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/species/SpeciesCollectionXmlParserTest.java b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/species/SpeciesCollectionXmlParserTest.java index 8dcfc0e81042f939ad4c66ce8f98fb0c6944d07b..1c1cdcb38b1ba051a7e56e17271441433c4db7f6 100644 --- a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/species/SpeciesCollectionXmlParserTest.java +++ b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/species/SpeciesCollectionXmlParserTest.java @@ -3,8 +3,7 @@ package lcsb.mapviewer.converter.model.celldesigner.species; import static org.junit.Assert.*; import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.List; +import java.util.*; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -41,7 +40,7 @@ public class SpeciesCollectionXmlParserTest extends CellDesignerTestFunctions { @Before public void setUp() throws Exception { elements = new CellDesignerElementCollection(); - parser = new SpeciesCollectionXmlParser(elements); + parser = new SpeciesCollectionXmlParser(elements, new HashSet<>()); } @After @@ -292,7 +291,7 @@ public class SpeciesCollectionXmlParserTest extends CellDesignerTestFunctions { // this is only for test coverage purpose - SpeciesCollectionXmlParser parser = new SpeciesCollectionXmlParser(elements); + SpeciesCollectionXmlParser parser = new SpeciesCollectionXmlParser(elements, new HashSet<>()); Field field = SpeciesCollectionXmlParser.class.getDeclaredField("helpParser"); field.setAccessible(true); try { diff --git a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/species/SpeciesSbmlParserTest.java b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/species/SpeciesSbmlParserTest.java index 191980708730fe87dc2e5a735fcf8b9393b465d3..69f57b7473f3e5cca1ead7bc33ae806cd92e57e1 100644 --- a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/species/SpeciesSbmlParserTest.java +++ b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/species/SpeciesSbmlParserTest.java @@ -3,6 +3,7 @@ package lcsb.mapviewer.converter.model.celldesigner.species; import static org.junit.Assert.*; import java.io.StringReader; +import java.util.HashSet; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -45,7 +46,7 @@ public class SpeciesSbmlParserTest extends CellDesignerTestFunctions { @Before public void setUp() throws Exception { elements = new CellDesignerElementCollection(); - parser = new SpeciesSbmlParser(elements); + parser = new SpeciesSbmlParser(elements, new HashSet<>()); } @After @@ -269,7 +270,7 @@ public class SpeciesSbmlParserTest extends CellDesignerTestFunctions { InternalModelSpeciesData modelData = new InternalModelSpeciesData(); modelData.updateSpecies(gene, ""); - SpeciesSbmlParser complexParser = new SpeciesSbmlParser(elements); + SpeciesSbmlParser complexParser = new SpeciesSbmlParser(elements, new HashSet<>()); CellDesignerGene oldGene = new CellDesignerGene(); oldGene.setElementId("s5916"); oldGene.setName("Ptgr1"); diff --git a/converter-CellDesigner/testFiles/problematic/substance_defined_as_type.xml b/converter-CellDesigner/testFiles/problematic/substance_defined_as_type.xml new file mode 100644 index 0000000000000000000000000000000000000000..cba3c6f7d241ff8f28340fe4040d68a9223f117e --- /dev/null +++ b/converter-CellDesigner/testFiles/problematic/substance_defined_as_type.xml @@ -0,0 +1,126 @@ +<?xml version="1.0" encoding="UTF-8"?> +<sbml xmlns="http://www.sbml.org/sbml/level2/version4" xmlns:celldesigner="http://www.sbml.org/2001/ns/celldesigner" level="2" version="4"> +<model metaid="CellDesigner_Ver_42_Components" id="CellDesigner_Ver_42_Components" sboTerm="SBO:0000231"> +<notes> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<title/> +</head> +<body>This is a sample file for CellDesigner 4.2, describing the graphical notation. +http://celldesigner.org +</body> +</html> +</notes> +<annotation> +<celldesigner:extension> +<celldesigner:modelVersion>4.0</celldesigner:modelVersion> +<celldesigner:modelDisplay sizeX="1700" sizeY="1200"/> +<celldesigner:listOfCompartmentAliases/> +<celldesigner:listOfComplexSpeciesAliases/> +<celldesigner:listOfSpeciesAliases> +<celldesigner:speciesAlias id="a1" species="s198"> +<celldesigner:activity>inactive</celldesigner:activity> +<celldesigner:bounds x="123.25" y="47.20381061236179" w="80.0" h="40.0"/> +<celldesigner:font size="12"/> +<celldesigner:view state="usual"/> +<celldesigner:usualView> +<celldesigner:boxSize width="80.0" height="40.0"/> +<celldesigner:singleLine width="1.0"/> +<celldesigner:paint color="ffccffcc" scheme="Color"/> +</celldesigner:usualView> +<celldesigner:briefView> +<celldesigner:innerPosition x="0.0" y="0.0"/> +<celldesigner:boxSize width="80.0" height="60.0"/> +<celldesigner:singleLine width="1.0"/> +<celldesigner:paint color="3fff0000" scheme="Color"/> +</celldesigner:briefView> +<celldesigner:info state="empty" angle="-1.5707963267948966"/> +</celldesigner:speciesAlias> +</celldesigner:listOfSpeciesAliases> +<celldesigner:listOfGroups/> +<celldesigner:listOfProteins> +<celldesigner:protein id="p1" name="Protein" type="GENERIC"/> +</celldesigner:listOfProteins> +<celldesigner:listOfGenes/> +<celldesigner:listOfRNAs/> +<celldesigner:listOfAntisenseRNAs/> +<celldesigner:listOfLayers> +<celldesigner:layer id="1" name="comment" locked="false" visible="true"/> +</celldesigner:listOfLayers> +<celldesigner:listOfBlockDiagrams/> +</celldesigner:extension> +<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:vCard="http://www.w3.org/2001/vcard-rdf/3.0#" xmlns:bqbiol="http://biomodels.net/biology-qualifiers/" xmlns:bqmodel="http://biomodels.net/model-qualifiers/"> +<rdf:Description rdf:about="#CellDesigner_Ver_42_Components"> +<dc:creator> +<rdf:Bag> +<rdf:li rdf:parseType="Resource"> +<vCard:EMAIL>info@celldesigner.org</vCard:EMAIL> +<vCard:ORG rdf:parseType="Resource"> +<vCard:Orgname>The Systems Biology Institute</vCard:Orgname> +</vCard:ORG> +</rdf:li> +</rdf:Bag> +</dc:creator> +<dcterms:created rdf:parseType="Resource"> +<dcterms:W3CDTF>2009-07-13T20:39:30Z</dcterms:W3CDTF> +</dcterms:created> +<dcterms:modified rdf:parseType="Resource"> +<dcterms:W3CDTF>2011-03-09T19:11:39Z</dcterms:W3CDTF> +</dcterms:modified> +</rdf:Description> +</rdf:RDF> +</annotation> +<listOfUnitDefinitions> +<unitDefinition metaid="substance" id="substance" name="substance"> +<listOfUnits> +<unit metaid="CDMT00121" kind="mole"/> +</listOfUnits> +</unitDefinition> +<unitDefinition metaid="volume" id="volume" name="volume"> +<listOfUnits> +<unit metaid="CDMT00122" kind="litre"/> +</listOfUnits> +</unitDefinition> +<unitDefinition metaid="area" id="area" name="area"> +<listOfUnits> +<unit metaid="CDMT00123" kind="metre" exponent="2"/> +</listOfUnits> +</unitDefinition> +<unitDefinition metaid="length" id="length" name="length"> +<listOfUnits> +<unit metaid="CDMT00124" kind="metre"/> +</listOfUnits> +</unitDefinition> +<unitDefinition metaid="time" id="time" name="time"> +<listOfUnits> +<unit metaid="CDMT00125" kind="second"/> +</listOfUnits> +</unitDefinition> +</listOfUnitDefinitions> +<listOfCompartments> +<compartment metaid="default" id="default" size="1" units="volume" sboTerm="SBO:0000240"/> +</listOfCompartments> +<listOfSpecies> +<species metaid="s198" id="s198" name="Protein" compartment="default" initialAmount="0" substanceUnits="substance" sboTerm="SBO:0000252"> +<notes> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<title/> +</head> +<body>You can input the Protein Notes here. +</body> +</html> +</notes> +<annotation> +<celldesigner:extension> +<celldesigner:positionToCompartment>inside</celldesigner:positionToCompartment> +<celldesigner:speciesIdentity> +<celldesigner:class>PROTEIN</celldesigner:class> +<celldesigner:proteinReference>p1</celldesigner:proteinReference> +</celldesigner:speciesIdentity> +</celldesigner:extension> +</annotation> +</species> +</listOfSpecies> +</model> +</sbml> diff --git a/converter/src/main/java/lcsb/mapviewer/converter/annotation/XmlAnnotationParser.java b/converter/src/main/java/lcsb/mapviewer/converter/annotation/XmlAnnotationParser.java index 4c811618c5ef54550290dcaa292a9faf0018a8a7..c5fda22de6cfac76ea539d8167f3755d6cda098f 100644 --- a/converter/src/main/java/lcsb/mapviewer/converter/annotation/XmlAnnotationParser.java +++ b/converter/src/main/java/lcsb/mapviewer/converter/annotation/XmlAnnotationParser.java @@ -320,8 +320,12 @@ public class XmlAnnotationParser { result.append("<rdf:Bag>\n"); result.append("<rdf:li rdf:parseType=\"Resource\">\n"); result.append("<vCard:N rdf:parseType=\"Resource\">\n"); - result.append("<vCard:Family>" + XmlParser.escapeXml(author.getLastName()) + "</vCard:Family>\n"); - result.append("<vCard:Given>" + XmlParser.escapeXml(author.getFirstName()) + "</vCard:Given>\n"); + if (author.getLastName() != null) { + result.append("<vCard:Family>" + XmlParser.escapeXml(author.getLastName()) + "</vCard:Family>\n"); + } + if (author.getFirstName() != null) { + result.append("<vCard:Given>" + XmlParser.escapeXml(author.getFirstName()) + "</vCard:Given>\n"); + } result.append("</vCard:N>\n"); if (author.getEmail() != null && !author.getEmail().trim().isEmpty()) { diff --git a/model/src/main/java/lcsb/mapviewer/model/map/species/Species.java b/model/src/main/java/lcsb/mapviewer/model/map/species/Species.java index 22b065e41aa5f740ef1177fbb44d2e46e115744b..19eb0d2e4b88567723e5fea893e6483cea81f641 100644 --- a/model/src/main/java/lcsb/mapviewer/model/map/species/Species.java +++ b/model/src/main/java/lcsb/mapviewer/model/map/species/Species.java @@ -10,6 +10,7 @@ import org.apache.logging.log4j.Logger; import org.hibernate.annotations.Cascade; import org.hibernate.annotations.CascadeType; +import lcsb.mapviewer.model.map.kinetics.SbmlUnit; import lcsb.mapviewer.model.map.kinetics.SbmlUnitType; import lcsb.mapviewer.model.map.species.field.PositionToCompartment; import lcsb.mapviewer.model.map.species.field.UniprotRecord; @@ -120,8 +121,23 @@ public abstract class Species extends Element { private Boolean constant = false; + /** + * SBML allows to store substanceUnit as either basic SI unit type or complex + * unit definition. To map it properly to database we need to separate the type + * into two properties. This property is responsible for basic SI unit type. + */ @Enumerated(EnumType.STRING) - private SbmlUnitType substanceUnits; + private SbmlUnitType substanceUnitRawType; + + /** + * SBML allows to store substanceUnit as either basic SI unit type or complex + * unit definition. To map it properly to database we need to separate the type + * into two properties. This property is responsible for complex unit + * definition. + */ + @ManyToOne + @Cascade({ CascadeType.ALL }) + private SbmlUnit substanceUnitComlexType; /** * Constructor that set element identifier. @@ -171,7 +187,8 @@ public abstract class Species extends Element { hypothetical = original.getHypothetical(); boundaryCondition = original.getBoundaryCondition(); constant = original.getConstant(); - substanceUnits = original.getSubstanceUnits(); + substanceUnitComlexType = original.substanceUnitComlexType; + substanceUnitRawType = original.substanceUnitRawType; uniprots = original.getUniprots(); @@ -476,12 +493,22 @@ public abstract class Species extends Element { this.constant = constant; } - public SbmlUnitType getSubstanceUnits() { - return substanceUnits; + public Object getSubstanceUnits() { + if (this.substanceUnitRawType != null) { + return this.substanceUnitRawType; + } else { + return this.substanceUnitComlexType; + } } public void setSubstanceUnits(SbmlUnitType substanceUnits) { - this.substanceUnits = substanceUnits; + this.substanceUnitRawType = substanceUnits; + this.substanceUnitComlexType = null; + } + + public void setSubstanceUnits(SbmlUnit substanceUnits) { + this.substanceUnitComlexType = substanceUnits; + this.substanceUnitRawType = null; } } diff --git a/model/src/main/java/lcsb/mapviewer/model/map/species/SpeciesComparator.java b/model/src/main/java/lcsb/mapviewer/model/map/species/SpeciesComparator.java index 5aed73eaf242cd8f0bc0068906b23517c73a0254..aad1de4fb320d9fa9cfa9337a0aa28495d3c0574 100644 --- a/model/src/main/java/lcsb/mapviewer/model/map/species/SpeciesComparator.java +++ b/model/src/main/java/lcsb/mapviewer/model/map/species/SpeciesComparator.java @@ -6,7 +6,7 @@ import org.apache.logging.log4j.Logger; import lcsb.mapviewer.common.Comparator; import lcsb.mapviewer.common.Configuration; import lcsb.mapviewer.common.comparator.*; -import lcsb.mapviewer.model.map.kinetics.SbmlUnitType; +import lcsb.mapviewer.model.map.kinetics.*; /** * Comparator class used for comparing {@link Species} objects. @@ -145,11 +145,32 @@ public class SpeciesComparator extends Comparator<Species> { return booleanComparator.compare(arg0.isBoundaryCondition(), arg1.isBoundaryCondition()); } - EnumComparator<SbmlUnitType> enumComparator = new EnumComparator<>(); - if (enumComparator.compare(arg0.getSubstanceUnits(), arg1.getSubstanceUnits()) != 0) { + EnumComparator<SbmlUnitType> unitTypeComparator = new EnumComparator<>(); + SbmlUnitComparator unitComparator = new SbmlUnitComparator(); + SbmlUnitType sbmlUnitType1 = null; + SbmlUnitType sbmlUnitType2 = null; + + SbmlUnit sbmlUnit1 = null; + SbmlUnit sbmlUnit2 = null; + if (arg0.getSubstanceUnits() instanceof SbmlUnit) { + sbmlUnit1 = (SbmlUnit) arg0.getSubstanceUnits(); + } else { + sbmlUnitType1 = (SbmlUnitType) arg0.getSubstanceUnits(); + } + if (arg1.getSubstanceUnits() instanceof SbmlUnit) { + sbmlUnit2 = (SbmlUnit) arg1.getSubstanceUnits(); + } else { + sbmlUnitType2 = (SbmlUnitType) arg1.getSubstanceUnits(); + } + if (unitTypeComparator.compare(sbmlUnitType1, sbmlUnitType2) != 0) { + logger.debug( + "SubstanceUnits different: \"" + arg0.getSubstanceUnits() + "\", \"" + arg1.getSubstanceUnits() + "\""); + return unitTypeComparator.compare(sbmlUnitType1, sbmlUnitType2); + } + if (unitComparator.compare(sbmlUnit1, sbmlUnit2) != 0) { logger.debug( "SubstanceUnits different: \"" + arg0.getSubstanceUnits() + "\", \"" + arg1.getSubstanceUnits() + "\""); - return enumComparator.compare(arg0.getSubstanceUnits(), arg1.getSubstanceUnits()); + return unitComparator.compare(sbmlUnit1, sbmlUnit2); } return 0; diff --git a/persist/src/main/resources/db/migration/14.0.3/V14.0.1.20191016__substance_unit_complex_type.sql b/persist/src/main/resources/db/migration/14.0.3/V14.0.1.20191016__substance_unit_complex_type.sql new file mode 100644 index 0000000000000000000000000000000000000000..48134aea4e6c1fa9387c84954191ce3fc96dc35a --- /dev/null +++ b/persist/src/main/resources/db/migration/14.0.3/V14.0.1.20191016__substance_unit_complex_type.sql @@ -0,0 +1,3 @@ +alter table element_table add column substance_unit_comlex_type_id integer; +alter table element_table add foreign key (substance_unit_comlex_type_id) references sbml_unit_table(id); +alter table element_table rename column substance_units to substance_unit_raw_type;