diff --git a/CHANGELOG b/CHANGELOG index 760cc113b090bc3d7b3f06313f998ef5ca95bf96..1c7ea17cbb32e6090c0a017304601d18ba31e608 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,7 @@ minerva (15.0.0~beta.2) stable; urgency=medium structured log form * Bug fix: antisenseRNA shape is infered from SBGN when antisenseRNA text is present in glyph label (#1114) + * Bug fix: export to SBGN sometimes crashed due to concurrency issues (#1126) -- Piotr Gawron Wed, 27 Feb 2020 14:00:00 +0200 diff --git a/model-command/src/main/java/lcsb/mapviewer/commands/CopyCommand.java b/model-command/src/main/java/lcsb/mapviewer/commands/CopyCommand.java index 214b1df6f7e924e52ab7d33210f44b0f789587f8..a6bc5de9659ba690c5fb6c3523cd7d862102c659 100644 --- a/model-command/src/main/java/lcsb/mapviewer/commands/CopyCommand.java +++ b/model-command/src/main/java/lcsb/mapviewer/commands/CopyCommand.java @@ -277,11 +277,10 @@ public class CopyCommand extends NewModelCommand { * original reaction * @return copy of the reaction */ - private Reaction createCopy(Reaction reaction) { + Reaction createCopy(Reaction reaction) { Reaction copy = reaction.copy(); - reaction.getNodes().clear(); - for (AbstractNode node : copy.getNodes()) { - reaction.addNode(node); + for (AbstractNode node : reaction.getNodes()) { + node.setReaction(reaction); } copy.getNodes().clear(); diff --git a/model-command/src/test/java/lcsb/mapviewer/commands/CopyCommandTest.java b/model-command/src/test/java/lcsb/mapviewer/commands/CopyCommandTest.java index 129cb31e2b97d0754b65e4a9a3a1fddc36482e59..546d4ddf493d1c830125bab4d8ab0122d4ce3ad0 100644 --- a/model-command/src/test/java/lcsb/mapviewer/commands/CopyCommandTest.java +++ b/model-command/src/test/java/lcsb/mapviewer/commands/CopyCommandTest.java @@ -3,8 +3,9 @@ package lcsb.mapviewer.commands; import static org.junit.Assert.*; import java.awt.geom.Point2D; -import java.util.Calendar; +import java.util.*; +import org.apache.commons.lang3.mutable.MutableBoolean; import org.junit.*; import lcsb.mapviewer.common.exception.InvalidArgumentException; @@ -18,6 +19,7 @@ import lcsb.mapviewer.model.map.layout.graphics.Layer; import lcsb.mapviewer.model.map.model.*; import lcsb.mapviewer.model.map.reaction.*; import lcsb.mapviewer.model.map.reaction.type.StateTransitionReaction; +import lcsb.mapviewer.model.map.reaction.type.TransportReaction; import lcsb.mapviewer.model.map.species.*; public class CopyCommandTest extends CommandTestFunctions { @@ -312,4 +314,47 @@ public class CopyCommandTest extends CommandTestFunctions { assertEquals(0, comparator.compare(copy, model)); } + @Test + public void testMultithreadedCopyReaction() throws Exception { + MutableBoolean exceptionHappened = new MutableBoolean(false); + Reaction r = new TransportReaction("x"); + r.addReactant(new Reactant(createProtein())); + r.addReactant(new Reactant(createProtein())); + r.addReactant(new Reactant(createProtein())); + r.addReactant(new Reactant(createProtein())); + r.addProduct(new Product(createProtein())); + for (AbstractNode node : r.getNodes()) { + node.setLine(new PolylineData(new Point2D.Double(0.0, 0.0), new Point2D.Double(110.0, 10.0))); + } + + List threads = new ArrayList<>(); + for (int i = 0; i < 100; i++) { + threads.add(new Thread(new Runnable() { + + @Override + public void run() { + try { + new CopyCommand(null).createCopy(r); + } catch (Exception e) { + e.printStackTrace(); + exceptionHappened.setTrue(); + } + } + })); + } + for (Thread thread : threads) { + thread.start(); + } + for (Thread thread : threads) { + thread.join(); + } + + assertFalse(exceptionHappened.booleanValue()); + + for (AbstractNode node : r.getNodes()) { + assertEquals(r, node.getReaction()); + } + + } + }