diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/reaction/SbmlReactionParser.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/reaction/SbmlReactionParser.java index e3614d5bb4eda32a71b24d0b6229cdde783a253e..3840b12cdd855ca3d7ed1a3a200387e9e36c3f8b 100644 --- a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/reaction/SbmlReactionParser.java +++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/reaction/SbmlReactionParser.java @@ -51,6 +51,7 @@ import lcsb.mapviewer.model.map.reaction.AbstractNode; import lcsb.mapviewer.model.map.reaction.AndOperator; import lcsb.mapviewer.model.map.reaction.AssociationOperator; import lcsb.mapviewer.model.map.reaction.DissociationOperator; +import lcsb.mapviewer.model.map.reaction.InvalidReactionParticipantNumberException; import lcsb.mapviewer.model.map.reaction.Modifier; import lcsb.mapviewer.model.map.reaction.NodeOperator; import lcsb.mapviewer.model.map.reaction.Product; @@ -453,14 +454,34 @@ public class SbmlReactionParser extends SbmlBioEntityParser { } } + String sboTerm = sbmlReaction.getSBOTermID(); + + reaction = createProperReactionClassForSboTerm(reaction, sboTerm); + + return reaction; + } + + private Reaction createProperReactionClassForSboTerm(Reaction reaction, String sboTerm) + throws InvalidInputDataExecption { + Class<? extends Reaction> reactionClass = SBOTermReactionType.getTypeSBOTerm(sboTerm); try { - Class<? extends Reaction> reactionClass = SBOTermReactionType.getTypeSBOTerm(sbmlReaction.getSBOTermID()); reaction = reactionClass.getConstructor(Reaction.class).newInstance(reaction); } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) { - throw new InvalidInputDataExecption("Problem with creating reaction", e); + if (e.getCause() instanceof InvalidReactionParticipantNumberException) { + try { + logger.warn(eu.getElementTag(reaction) + "SBO term indicated " + reactionClass.getSimpleName() + + " class. However number of reactants/products is insufficient for such class type. Using default."); + reactionClass = SBOTermReactionType.getTypeSBOTerm(null); + reaction = reactionClass.getConstructor(Reaction.class).newInstance(reaction); + } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException + | NoSuchMethodException | SecurityException e1) { + throw new InvalidInputDataExecption(eu.getElementTag(reaction) + "Problem with creating reaction", e); + } + } else { + throw new InvalidInputDataExecption(eu.getElementTag(reaction) + "Problem with creating reaction", e); + } } - return reaction; } diff --git a/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/SbmlParserTest.java b/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/SbmlParserTest.java index 8f1cc44b8194b62c33423b5ec454f01dc07e24e1..6904550a3b34d016817ade64be5903d96949fef7 100644 --- a/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/SbmlParserTest.java +++ b/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/SbmlParserTest.java @@ -159,6 +159,17 @@ public class SbmlParserTest { new ConverterParams().filename("testFiles/invalidReaction/reaction_with_missing_part_of_layout.xml")); } + @Test + public void test() throws Exception { + try { + parser.createModel( + new ConverterParams().filename("/home/gawi/Desktop/biomodels/BIOMD0000000001_url.xml")); + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + @Test public void testDefaultColors() throws Exception { Model model = parser.createModel(new ConverterParams().filename("testFiles/small/default_colors.xml")); diff --git a/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/reaction/SbmlReactionParserTest.java b/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/reaction/SbmlReactionParserTest.java index f54fa31e7325844e2cb19c60ea7ee28d5b41604c..a5a64fa45128ca6f169bc1256ee616a0a94a2017 100644 --- a/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/reaction/SbmlReactionParserTest.java +++ b/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/reaction/SbmlReactionParserTest.java @@ -125,6 +125,21 @@ public class SbmlReactionParserTest { assertTrue(reaction instanceof HeterodimerAssociationReaction); } + @Test + public void testParseHeterodimerAssociationWithSingleReactant() throws Exception { + try { + Model model = parser + .createModel(new ConverterParams() + .filename("testFiles/small/reaction/heterodimer_association_with_single_reactant.xml")); + Reaction reaction = model.getReactions().iterator().next(); + assertNotNull(reaction); + assertTrue(reaction instanceof Reaction); + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + @Test public void testParseDissociation() throws FileNotFoundException, InvalidInputDataExecption { Model model = parser.createModel(new ConverterParams().filename("testFiles/small/reaction/dissociation.xml")); diff --git a/converter-sbml/testFiles/small/reaction/heterodimer_association_with_single_reactant.xml b/converter-sbml/testFiles/small/reaction/heterodimer_association_with_single_reactant.xml new file mode 100644 index 0000000000000000000000000000000000000000..de28ae0c8cd360aab3c5a5f5db276c0c4b17777f --- /dev/null +++ b/converter-sbml/testFiles/small/reaction/heterodimer_association_with_single_reactant.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="UTF-8"?> +<sbml xmlns="http://www.sbml.org/sbml/level2/version4" level="2" version="4"> + <model id="TestGEN"> + <annotation/> + <listOfCompartments> + <compartment constant="true" id="cell" name="cell" sboTerm="SBO:0000290" size="1"> + <annotation> + <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:bqmodel="http://biomodels.net/model-qualifiers/" xmlns:bqbiol="http://biomodels.net/biology-qualifiers/"> + <rdf:Description rdf:about="#"> + <bqbiol:isVersionOf> + <rdf:Bag> + <rdf:li rdf:resource="urn:miriam:obo.go:GO:0005623"/> + </rdf:Bag> + </bqbiol:isVersionOf> + </rdf:Description> + </rdf:RDF> + </annotation> + </compartment> + </listOfCompartments> + <listOfSpecies> + <species compartment="cell" initialConcentration="1" id="s1" name="nm1"> + <annotation/> + </species> + <species compartment="cell" initialConcentration="1" id="s2" name="nm2"> + <annotation/> + </species> + </listOfSpecies> + <listOfReactions> + <reaction id="re1" sboTerm="SBO:0000177"> + <listOfReactants> + <speciesReference species="s1" stoichiometry="1"/> + </listOfReactants> + <listOfProducts> + <speciesReference species="s2" stoichiometry="1"/> + </listOfProducts> + </reaction> + </listOfReactions> + </model> +</sbml> \ No newline at end of file diff --git a/model/src/main/java/lcsb/mapviewer/model/map/reaction/InvalidReactionParticipantNumberException.java b/model/src/main/java/lcsb/mapviewer/model/map/reaction/InvalidReactionParticipantNumberException.java new file mode 100644 index 0000000000000000000000000000000000000000..95c6c52c4d90e86baecb46aa8be832aded5107ee --- /dev/null +++ b/model/src/main/java/lcsb/mapviewer/model/map/reaction/InvalidReactionParticipantNumberException.java @@ -0,0 +1,59 @@ +package lcsb.mapviewer.model.map.reaction; + +import lcsb.mapviewer.common.exception.InvalidArgumentException; + +/** + * Exception to be thrown when number of reactants or products is invalid when + * creating reaction. + * + * @author Piotr Gawron + * + */ +public class InvalidReactionParticipantNumberException extends InvalidArgumentException { + /** + * + */ + private static final long serialVersionUID = 1L; + + /** + * Default constructor - initializes instance variable to unknown. + */ + + public InvalidReactionParticipantNumberException() { + super(); // call superclass constructor + } + + /** + * Public constructor with parent exception that was caught. + * + * @param e + * parent exception + */ + + public InvalidReactionParticipantNumberException(final String e) { + super(e); + } + + /** + * Public constructor with parent exception that was caught. + * + * @param e + * parent exception + */ + public InvalidReactionParticipantNumberException(final Exception e) { + super(e); + } + + /** + * Public constructor with parent exception that was caught. + * + * @param message + * exception message + * @param e + * parent exception + */ + public InvalidReactionParticipantNumberException(final String message, final Exception e) { + super(message, e); + } + +} diff --git a/model/src/main/java/lcsb/mapviewer/model/map/reaction/Reaction.java b/model/src/main/java/lcsb/mapviewer/model/map/reaction/Reaction.java index afa12884c7f1c6e288744fdf1e3e4077ef2d7b0d..bcabc050f42a742757c05d55251d5b93a4a4ea52 100644 --- a/model/src/main/java/lcsb/mapviewer/model/map/reaction/Reaction.java +++ b/model/src/main/java/lcsb/mapviewer/model/map/reaction/Reaction.java @@ -268,12 +268,12 @@ public class Reaction implements BioEntity { minProducts = 2; } if (original.getProducts().size() < minProducts) { - throw new InvalidArgumentException(new ElementUtils().getElementTag(original) + throw new InvalidReactionParticipantNumberException(new ElementUtils().getElementTag(original) + "Invalid source reaction: number of products must be at least " + minProducts); } if (original.getReactants().size() < minReactants) { - throw new InvalidArgumentException(new ElementUtils().getElementTag(original) + throw new InvalidReactionParticipantNumberException(new ElementUtils().getElementTag(original) + "Invalid source reaction: number of reactants must be at least " + minReactants); } }