From 82eee8811eb3d0b6ae137d0d7c7846bbb3eda669 Mon Sep 17 00:00:00 2001 From: Piotr Gawron <piotr.gawron@uni.lu> Date: Wed, 23 May 2018 11:42:54 +0200 Subject: [PATCH] when exporting reaction that has the same product and reactant system doesn't crash Instead of crashing reaction is omitted and proper info is added to the model notes. --- .../celldesigner/CellDesignerXmlParser.java | 78 +++++++++++-------- .../reaction/ReactionCollectionXmlParser.java | 4 + .../celldesigner/reaction/ReactionToXml.java | 4 + .../reaction/SelfReactionException.java | 31 ++++++++ .../CellDesignerXmlParserTest.java | 37 +++++++++ .../reaction/ReactionToXmlTest.java | 47 ++++++----- 6 files changed, 151 insertions(+), 50 deletions(-) create mode 100644 converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/reaction/SelfReactionException.java 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 6a7e6d10c7..8ab5a64b64 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 @@ -13,11 +13,13 @@ import java.util.List; import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang3.StringEscapeUtils; import org.apache.log4j.Logger; +import org.apache.log4j.spi.LoggingEvent; import org.apache.xerces.parsers.DOMParser; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; +import lcsb.mapviewer.common.EventStorageLoggerAppender; import lcsb.mapviewer.common.MimeType; import lcsb.mapviewer.common.Pair; import lcsb.mapviewer.common.XmlParser; @@ -563,47 +565,59 @@ public class CellDesignerXmlParser extends XmlParser implements IConverter { * thrown when then model is invalid * @throws InconsistentModelException */ - public String toXml(Model model) throws InconsistentModelException, InconsistentModelException { - CellDesignerElementCollection elements = new CellDesignerElementCollection(); + public String toXml(Model model) throws InconsistentModelException { + EventStorageLoggerAppender appender = new EventStorageLoggerAppender(); + try { + Logger.getRootLogger().addAppender(appender); + CellDesignerElementCollection elements = new CellDesignerElementCollection(); - SpeciesCollectionXmlParser speciesCollectionXmlParser = new SpeciesCollectionXmlParser(elements); - ReactionCollectionXmlParser reactionCollectionXmlParser = new ReactionCollectionXmlParser(model, elements, false); - UnitCollectionXmlParser unitCollectionXmlParser = new UnitCollectionXmlParser(); - FunctionCollectionXmlParser functionCollectionXmlParser = new FunctionCollectionXmlParser(); - ParameterCollectionXmlParser parameterCollectionXmlParser = new ParameterCollectionXmlParser(model); + SpeciesCollectionXmlParser speciesCollectionXmlParser = new SpeciesCollectionXmlParser(elements); + ReactionCollectionXmlParser reactionCollectionXmlParser = new ReactionCollectionXmlParser(model, elements, false); + UnitCollectionXmlParser unitCollectionXmlParser = new UnitCollectionXmlParser(); + FunctionCollectionXmlParser functionCollectionXmlParser = new FunctionCollectionXmlParser(); + ParameterCollectionXmlParser parameterCollectionXmlParser = new ParameterCollectionXmlParser(model); - aliasCollectionParser = new AliasCollectionXmlParser(elements, model); + aliasCollectionParser = new AliasCollectionXmlParser(elements, model); - StringBuilder result = new StringBuilder(); - result.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); - result.append("<sbml xmlns=\"http://www.sbml.org/sbml/level2/version4\" " - + "xmlns:celldesigner=\"http://www.sbml.org/2001/ns/celldesigner\" level=\"2\" version=\"4\">\n"); - // metaid is a string cell designer id, usually it's model id and as far as - // we can tell it's not used at all - result.append("<model metaid=\"" + model.getIdModel() + "\" id=\"" + model.getIdModel() + "\">\n"); - - if (model.getNotes() != null) { - result.append("<notes>"); - result.append(escapeXml(model.getNotes())); - result.append("</notes>"); - } + StringBuilder result = new StringBuilder(); + result.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); + result.append("<sbml xmlns=\"http://www.sbml.org/sbml/level2/version4\" " + + "xmlns:celldesigner=\"http://www.sbml.org/2001/ns/celldesigner\" level=\"2\" version=\"4\">\n"); + // metaid is a string cell designer id, usually it's model id and as far as + // we can tell it's not used at all + result.append("<model metaid=\"" + model.getIdModel() + "\" id=\"" + model.getIdModel() + "\">\n"); - result.append(unitCollectionXmlParser.toXml(model.getUnits())); - result.append(functionCollectionXmlParser.toXml(model.getFunctions())); - result.append(parameterCollectionXmlParser.toXml(model.getParameters())); - result.append(annotationToXml(model, elements)); + result.append(unitCollectionXmlParser.toXml(model.getUnits())); + result.append(functionCollectionXmlParser.toXml(model.getFunctions())); + result.append(parameterCollectionXmlParser.toXml(model.getParameters())); + result.append(annotationToXml(model, elements)); - compartmentCollectionXmlParser = new CompartmentCollectionXmlParser(elements); + compartmentCollectionXmlParser = new CompartmentCollectionXmlParser(elements); - result.append(compartmentCollectionXmlParser.toXml(model.getCompartments())); + result.append(compartmentCollectionXmlParser.toXml(model.getCompartments())); - result.append(speciesCollectionXmlParser.speciesCollectionToSbmlString(model.getSpeciesList())); + result.append(speciesCollectionXmlParser.speciesCollectionToSbmlString(model.getSpeciesList())); - result.append(reactionCollectionXmlParser.reactionCollectionToXmlString(model.getReactions())); + result.append(reactionCollectionXmlParser.reactionCollectionToXmlString(model.getReactions())); + if (model.getNotes() != null || !appender.getWarnings().isEmpty()) { + result.append("<notes>"); + if (model.getNotes() != null) { + result.append(escapeXml(model.getNotes())); + } + for (LoggingEvent event : appender.getWarnings()) { + if (event.getMessage() instanceof String) { + result.append("\n" + ((String) event.getMessage())); + } + } + result.append("</notes>"); + } - result.append("</model>"); - result.append("</sbml>"); - return result.toString(); + result.append("</model>"); + result.append("</sbml>"); + return result.toString(); + } finally { + Logger.getRootLogger().removeAppender(appender); + } } /** diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/reaction/ReactionCollectionXmlParser.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/reaction/ReactionCollectionXmlParser.java index e42618f464..cb8166ffe7 100644 --- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/reaction/ReactionCollectionXmlParser.java +++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/reaction/ReactionCollectionXmlParser.java @@ -101,7 +101,11 @@ public class ReactionCollectionXmlParser extends XmlParser { String result = ""; result += "<listOfReactions>\n"; for (Reaction reaction : collection) { + try { result += xmlStructureFactory.toXml(reaction); + } catch (SelfReactionException e) { + logger.warn("Reaction omitted: " + e.getMessage()); + } } result += "</listOfReactions>\n"; return result; diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/reaction/ReactionToXml.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/reaction/ReactionToXml.java index e1656a8ce4..7058ed10ec 100644 --- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/reaction/ReactionToXml.java +++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/reaction/ReactionToXml.java @@ -108,6 +108,10 @@ public class ReactionToXml extends XmlParser { * @throws ConverterException */ public String toXml(Reaction reaction) throws InconsistentModelException { + if (reaction.getReactants().get(0).getElement().equals(reaction.getProducts().get(0).getElement())) { + throw new SelfReactionException("Reaction " + reaction.getElementId() + " is a self reference for element " + + reaction.getProducts().get(0).getElement().getElementId()); + } StringBuilder sb = new StringBuilder(); sb.append("<reaction "); sb.append("metaid=\"" + reaction.getIdReaction() + "\" "); diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/reaction/SelfReactionException.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/reaction/SelfReactionException.java new file mode 100644 index 0000000000..b85d6f5537 --- /dev/null +++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/reaction/SelfReactionException.java @@ -0,0 +1,31 @@ +package lcsb.mapviewer.converter.model.celldesigner.reaction; + +import lcsb.mapviewer.model.map.InconsistentModelException; + +/** + * Exception thrown when CellDesigner exporter tries to export reaction that + * uses the same element as product and reactant. + * + * @author Piotr Gawron + * + */ +public class SelfReactionException extends InconsistentModelException { + /** + * + */ + private static final long serialVersionUID = 1L; + + /** + * Default constructor with a message passed in the argument. + * + * @param message + * text message of this exception + */ + public SelfReactionException(String message) { + super(message); + } + + public SelfReactionException(Exception e) { + super(e); + } +} 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 efa2ee8835..6f97c0fbcd 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 @@ -39,7 +39,10 @@ import lcsb.mapviewer.model.map.layout.graphics.LayerText; import lcsb.mapviewer.model.map.model.Model; import lcsb.mapviewer.model.map.model.ModelComparator; import lcsb.mapviewer.model.map.model.ModelFullIndexed; +import lcsb.mapviewer.model.map.reaction.Product; +import lcsb.mapviewer.model.map.reaction.Reactant; import lcsb.mapviewer.model.map.reaction.Reaction; +import lcsb.mapviewer.model.map.reaction.type.StateTransitionReaction; import lcsb.mapviewer.model.map.species.Element; import lcsb.mapviewer.model.map.species.Gene; import lcsb.mapviewer.model.map.species.GenericProtein; @@ -962,4 +965,38 @@ public class CellDesignerXmlParserTest extends CellDesignerTestFunctions { } } + @Test + public void testModelWithSelfReactionToXml() throws Exception { + try { + Model model = new ModelFullIndexed(null); + model.setIdModel("as"); + model.setWidth(10); + model.setHeight(10); + Species protein = new GenericProtein("id1"); + protein.setName("ROS"); + model.addElement(protein); + + Reaction reaction = new StateTransitionReaction(); + reaction.setIdReaction("re1"); + Product product = new Product(protein); + product.setLine(new PolylineData(new Point2D.Double(0, 0), new Point2D.Double(20, 20))); + reaction.addProduct(product); + Reactant reactant = new Reactant(protein); + reactant.setLine(new PolylineData(new Point2D.Double(20, 20), new Point2D.Double(0, 0))); + reaction.addReactant(reactant); + model.addReaction(reaction); + + CellDesignerXmlParser parser = new CellDesignerXmlParser(); + String xmlString = parser.toXml(model); + + assertNotNull(xmlString); + assertTrue(xmlString.contains("omitted")); + assertTrue(xmlString.contains("re1")); + + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + } diff --git a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/reaction/ReactionToXmlTest.java b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/reaction/ReactionToXmlTest.java index fdc5a88fc6..892243e5b3 100644 --- a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/reaction/ReactionToXmlTest.java +++ b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/reaction/ReactionToXmlTest.java @@ -57,24 +57,26 @@ public class ReactionToXmlTest { @Test public void testInvalidModification() throws InconsistentModelException { Model model = new ModelFullIndexed(null); - Species alias = new GenericProtein("2"); + Species protein1 = new GenericProtein("2"); + Species protein2 = new GenericProtein("3"); - model.addElement(alias); + model.addElement(protein1); + model.addElement(protein2); Reaction reaction = new TransportReaction(); - Reactant reactant = new Reactant(alias); + Reactant reactant = new Reactant(protein1); reactant.setLine(new PolylineData(new Point2D.Double(), new Point2D.Double(10, 0))); - Product product = new Product(alias); + Product product = new Product(protein2); product.setLine(new PolylineData(new Point2D.Double(), new Point2D.Double(20, 0))); reaction.addReactant(reactant); reaction.addProduct(product); - Modifier modifier = new Catalysis(alias); + Modifier modifier = new Catalysis(protein1); modifier.setLine(new PolylineData(new Point2D.Double(), new Point2D.Double(30, 0))); - Modifier modifier2 = new Catalysis(alias); + Modifier modifier2 = new Catalysis(protein1); List<Point2D> points = new ArrayList<>(); points.add(new Point2D.Double(0, 0)); points.add(new Point2D.Double(30, 30)); @@ -114,28 +116,30 @@ public class ReactionToXmlTest { public void testModificationFromInsideComplex() throws InconsistentModelException { Model model = new ModelFullIndexed(null); - Species alias = new GenericProtein("2"); + Species protein1 = new GenericProtein("2"); + Species protein2 = new GenericProtein("3"); - model.addElement(alias); + model.addElement(protein1); + model.addElement(protein2); Complex complex = new Complex("4"); - complex.addSpecies(alias); + complex.addSpecies(protein1); - alias.setComplex(complex); + protein1.setComplex(complex); model.addElement(complex); Reaction reaction = new TransportReaction(); - Reactant reactant = new Reactant(alias); + Reactant reactant = new Reactant(protein1); reactant.setLine(new PolylineData(new Point2D.Double(), new Point2D.Double(10, 0))); - Product product = new Product(alias); + Product product = new Product(protein2); product.setLine(new PolylineData(new Point2D.Double(), new Point2D.Double(20, 0))); reaction.addReactant(reactant); reaction.addProduct(product); - Modifier modifier = new Catalysis(alias); + Modifier modifier = new Catalysis(protein1); modifier.setLine(new PolylineData(new Point2D.Double(), new Point2D.Double(30, 0))); reaction.addModifier(modifier); @@ -154,12 +158,17 @@ public class ReactionToXmlTest { Complex complex = new Complex("4"); complex.setComplex(complex); model.addElement(complex); + + Species protein1 = new GenericProtein("2"); + + model.addElement(protein1); + Reaction reaction = new TransportReaction(); Reactant reactant = new Reactant(complex); reactant.setLine(new PolylineData(new Point2D.Double(), new Point2D.Double(10, 0))); - Product product = new Product(complex); + Product product = new Product(protein1); product.setLine(new PolylineData(new Point2D.Double(), new Point2D.Double(20, 0))); reaction.addReactant(reactant); @@ -178,15 +187,17 @@ public class ReactionToXmlTest { public void testInvalidReaction() throws InconsistentModelException { Model model = new ModelFullIndexed(null); - Species alias = new GenericProtein("2"); + Species protein1 = new GenericProtein("2"); + Species protein2 = new GenericProtein("3"); - model.addElement(alias); + model.addElement(protein1); + model.addElement(protein2); Reaction reaction = new Reaction(); - Reactant reactant = new Reactant(alias); + Reactant reactant = new Reactant(protein1); reactant.setLine(new PolylineData(new Point2D.Double(), new Point2D.Double(10, 0))); - Product product = new Product(alias); + Product product = new Product(protein2); product.setLine(new PolylineData(new Point2D.Double(), new Point2D.Double(20, 0))); reaction.addReactant(reactant); -- GitLab