diff --git a/model-command/src/main/java/lcsb/mapviewer/commands/SubModelCommand.java b/model-command/src/main/java/lcsb/mapviewer/commands/SubModelCommand.java index 0ab7ea8d342d85d8b1df2ed67da5d0511292b20a..b1e301093a37e90c7e003adfb607acfadd20ca73 100644 --- a/model-command/src/main/java/lcsb/mapviewer/commands/SubModelCommand.java +++ b/model-command/src/main/java/lcsb/mapviewer/commands/SubModelCommand.java @@ -6,14 +6,15 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import org.apache.log4j.Logger; + import lcsb.mapviewer.model.map.layout.graphics.Layer; import lcsb.mapviewer.model.map.layout.graphics.LayerText; import lcsb.mapviewer.model.map.model.Model; -import lcsb.mapviewer.model.map.reaction.AbstractNode; 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.Complex; +import lcsb.mapviewer.model.map.species.Element; import lcsb.mapviewer.model.map.species.Species; /** @@ -24,118 +25,160 @@ import lcsb.mapviewer.model.map.species.Species; * */ public class SubModelCommand extends NewModelCommand { - - /** - * Polygon that limits the area for the new model. - * - */ - private Path2D polygon; - - /** - * Default constructor. - * - * @param model - * original {@link NewModelCommand#model} - * @param polygon - * #polygon that limits the area for the new model - */ - public SubModelCommand(Model model, Path2D polygon) { - super(model); - this.polygon = polygon; - } - - @Override - public Model execute() { - CopyCommand copy = new CopyCommand(getModel()); - Model result = copy.execute(); - - Set<Element> aliasNotToRemove = new HashSet<Element>(); - - for (Element alias : result.getElements()) { - if (polygon.intersects(alias.getBorder())) { - aliasNotToRemove.add(alias); - } - } - boolean added = false; - do { - Set<Element> iterativeAliasNotToRemove = new HashSet<>(); - for (Element alias : aliasNotToRemove) { - Element parent = alias.getCompartment(); - if (parent != null) { - if (!aliasNotToRemove.contains(parent)) { - iterativeAliasNotToRemove.add(parent); - } - } - if (alias instanceof Species) { - parent = ((Species) alias).getComplex(); - if (parent != null) { - if (!aliasNotToRemove.contains(parent)) { - iterativeAliasNotToRemove.add(parent); - } - } - } - } - - added = iterativeAliasNotToRemove.size() != 0; - aliasNotToRemove.addAll(iterativeAliasNotToRemove); - } while (added); - - List<Element> aliasToRemove = new ArrayList<Element>(); - for (Element alias : result.getElements()) { - if (!(polygon.intersects(alias.getBorder()))) { - boolean remove = true; - if (alias instanceof Species) { - remove = ((Species) alias).getComplex() == null; - } - if (aliasNotToRemove.contains(alias)) { - remove = false; - } - if (remove) { - aliasToRemove.add(alias); - if (alias instanceof Complex) { - List<Species> aliases = ((Complex) alias).getAllChildren(); - aliasToRemove.addAll(aliases); - } - } - } - - } - for (Element alias : aliasToRemove) { - result.removeElement(alias); - } - - List<Reaction> reactionsToRemove = new ArrayList<Reaction>(); - for (Reaction reaction : result.getReactions()) { - boolean remove = false; - for (AbstractNode node : reaction.getNodes()) { - if (node instanceof ReactionNode) { - if (!result.getElements().contains(((ReactionNode) node).getElement())) { - remove = true; - break; - } - } - } - if (remove) { - reactionsToRemove.add(reaction); - } - } - for (Reaction reaction : reactionsToRemove) { - result.removeReaction(reaction); - } - - for (Layer layer : result.getLayers()) { - List<LayerText> textToRemove = new ArrayList<LayerText>(); - for (LayerText text : layer.getTexts()) { - if (!(polygon.intersects(text.getBorder()))) { - textToRemove.add(text); - } - } - for (LayerText text : textToRemove) { - layer.removeLayerText(text); - } - } - - return result; - } + + Logger logger = Logger.getLogger(SubModelCommand.class); + + /** + * Polygon that limits the area for the new model. + * + */ + private Path2D polygon; + + private Set<Integer> elementIds; + + private Set<Integer> reactionIds; + + /** + * Default constructor. + * + * @param model + * original {@link NewModelCommand#model} + * @param polygon + * #polygon that limits the area for the new model + */ + public SubModelCommand(Model model, Path2D polygon) { + this(model, polygon, new HashSet<>(), new HashSet<>()); + } + + /** + * Default constructor. + * + * @param model + * original {@link NewModelCommand#model} + * @param polygon + * #polygon that limits the area for the new model + */ + public SubModelCommand(Model model, Path2D polygon, Set<Integer> elementIds, Set<Integer> reactionIds) { + super(model); + this.polygon = polygon; + this.elementIds = elementIds; + this.reactionIds = reactionIds; + } + + @Override + public Model execute() { + CopyCommand copy = new CopyCommand(getModel()); + Model result = copy.execute(); + + Set<Element> inputElements = new HashSet<>(); + if (elementIds.size() == 0) { + inputElements.addAll(result.getElements()); + } else { + for (Element element : getModel().getElements()) { + if (elementIds.contains(element.getId())) { + inputElements.add(result.getElementByElementId(element.getElementId())); + } + } + } + + Set<Element> aliasNotToRemove = new HashSet<>(); + + for (Element alias : result.getElements()) { + if (polygon.intersects(alias.getBorder())) { + aliasNotToRemove.add(alias); + } + } + aliasNotToRemove.retainAll(inputElements); + + boolean added = false; + do { + Set<Element> iterativeAliasNotToRemove = new HashSet<>(); + for (Element alias : aliasNotToRemove) { + Element parent = alias.getCompartment(); + if (parent != null) { + if (!aliasNotToRemove.contains(parent)) { + iterativeAliasNotToRemove.add(parent); + } + } + if (alias instanceof Species) { + parent = ((Species) alias).getComplex(); + if (parent != null) { + if (!aliasNotToRemove.contains(parent)) { + iterativeAliasNotToRemove.add(parent); + } + } + } + } + + added = iterativeAliasNotToRemove.size() != 0; + aliasNotToRemove.addAll(iterativeAliasNotToRemove); + } while (added); + + List<Element> aliasToRemove = new ArrayList<>(); + for (Element element : result.getElements()) { + if (!(polygon.intersects(element.getBorder())) || !inputElements.contains(element)) { + boolean remove = true; + if (element instanceof Species) { + remove = ((Species) element).getComplex() == null; + } + if (aliasNotToRemove.contains(element)) { + remove = false; + } + if (remove) { + aliasToRemove.add(element); + if (element instanceof Complex) { + List<Species> aliases = ((Complex) element).getAllChildren(); + aliasToRemove.addAll(aliases); + } + } + } + + } + for (Element alias : aliasToRemove) { + result.removeElement(alias); + } + + Set<String> reactionStringIds = new HashSet<>(); + for (Reaction reaction : getModel().getReactions()) { + if (reactionIds.size() == 0 || reactionIds.contains(reaction.getId())) { + reactionStringIds.add(reaction.getElementId()); + } + } + + List<Reaction> reactionsToRemove = new ArrayList<>(); + for (Reaction reaction : result.getReactions()) { + boolean remove = false; + if (!reactionStringIds.contains(reaction.getElementId())) { + remove = true; + } else { + for (ReactionNode node : reaction.getReactionNodes()) { + if (!result.getElements().contains(node.getElement())) { + remove = true; + break; + } + } + } + if (remove) { + reactionsToRemove.add(reaction); + } + } + for (Reaction reaction : reactionsToRemove) { + result.removeReaction(reaction); + } + + for (Layer layer : result.getLayers()) { + List<LayerText> textToRemove = new ArrayList<>(); + for (LayerText text : layer.getTexts()) { + if (!(polygon.intersects(text.getBorder()))) { + textToRemove.add(text); + } + } + for (LayerText text : textToRemove) { + layer.removeLayerText(text); + } + } + + return result; + } } diff --git a/model-command/src/test/java/lcsb/mapviewer/commands/SubModelCommandTest.java b/model-command/src/test/java/lcsb/mapviewer/commands/SubModelCommandTest.java index ccfb0bb1adb1959a048126a8de13f1522eabff26..d4e7f30e6ed84db9ffad7a6caa4a5ebdacddf562 100644 --- a/model-command/src/test/java/lcsb/mapviewer/commands/SubModelCommandTest.java +++ b/model-command/src/test/java/lcsb/mapviewer/commands/SubModelCommandTest.java @@ -2,167 +2,245 @@ package lcsb.mapviewer.commands; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import java.awt.geom.Path2D; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.HashSet; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; import lcsb.mapviewer.converter.ConverterParams; import lcsb.mapviewer.converter.model.celldesigner.CellDesignerXmlParser; import lcsb.mapviewer.model.map.model.Model; import lcsb.mapviewer.model.map.model.ModelComparator; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - public class SubModelCommandTest extends CommandTestFunctions { - @Before - public void setUp() throws Exception { - } - - @After - public void tearDown() throws Exception { - } - - @Test - public void testGetSubmodel1() throws Exception { - try { - Model model = getModelForFile("testFiles/spliting_test_Case.xml", true); - - Path2D polygon = new Path2D.Double(); - polygon.moveTo(0, 0); - polygon.lineTo(0, 100); - polygon.lineTo(100, 100); - polygon.lineTo(100, 0); - polygon.closePath(); - - Model copy = new SubModelCommand(model, polygon).execute(); - - assertEquals(2, copy.getElements().size()); - assertEquals(0, copy.getReactions().size()); - - } catch (Exception e) { - e.printStackTrace(); - throw e; - } - } - - @Test - public void testGetSubmodel2() throws Exception { - try { - Model model = getModelForFile("testFiles/spliting_test_Case.xml", true); - - Path2D polygon = new Path2D.Double(); - polygon.moveTo(50, 50); - polygon.lineTo(350, 50); - polygon.lineTo(350, 200); - polygon.lineTo(50, 200); - polygon.closePath(); - - Model copy = new SubModelCommand(model, polygon).execute(); - - assertEquals(9, copy.getElements().size()); - assertEquals(1, copy.getReactions().size()); - - } catch (Exception e) { - e.printStackTrace(); - throw e; - } - } - - @Test - public void testGetSubmodel3() throws Exception { - try { - Model model = getModelForFile("testFiles/spliting_test_Case.xml", true); - - Path2D polygon = new Path2D.Double(); - polygon.moveTo(0, 200); - polygon.lineTo(350, 200); - polygon.lineTo(350, 400); - polygon.lineTo(0, 400); - polygon.closePath(); - - Model copy = new SubModelCommand(model, polygon).execute(); - - double dx = 10; - double dy = -10; - - new MoveCommand(copy, dx, dy).execute(); - - assertEquals(model.getElementByElementId("sa3").getCenterX(), copy.getElementByElementId("sa3").getCenterX() - dx, EPSILON); - assertEquals(model.getElementByElementId("sa3").getCenterY(), copy.getElementByElementId("sa3").getCenterY() - dy, EPSILON); - - assertEquals(model.getReactionByReactionId("re3").getLines().get(0).getX2(), copy.getReactionByReactionId("re3").getLines().get(0).getX2() - dx, EPSILON); - assertEquals(model.getReactionByReactionId("re3").getLines().get(0).getY2(), copy.getReactionByReactionId("re3").getLines().get(0).getY2() - dy, EPSILON); - - CellDesignerXmlParser parser = new CellDesignerXmlParser(); - String xml = parser.toXml(copy); - - InputStream stream = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8)); - Model copy2 = parser.createModel(new ConverterParams().inputStream(stream).sizeAutoAdjust(false)); - ModelComparator comparator = new ModelComparator(); - - // check if after conversion to xml everything works - assertEquals(0, comparator.compare(copy, copy2)); - } catch (Exception e) { - e.printStackTrace(); - throw e; - } - } - - @Test - public void testGetSubmodelWithoutCompartments() throws Exception { - try { - Model model = getModelForFile("testFiles/compartments.xml", true); - - Path2D polygon = new Path2D.Double(); - polygon.moveTo(0, 10); - polygon.lineTo(10, 10); - polygon.lineTo(10, 0); - polygon.lineTo(0, 0); - polygon.closePath(); - - Model copy = new SubModelCommand(model, polygon).execute(); - - // we should cut off some of compartmets - assertFalse(model.getLayers().iterator().next().getTexts().size() == copy.getLayers().iterator().next().getTexts().size()); - } catch (Exception e) { - e.printStackTrace(); - throw e; - } - } - - @Test - public void testGetSubmodelWithoutCompartments2() throws Exception { - try { - Model model = getModelForFile("testFiles/problematic/cutting_without_compartment.xml", true); - - Path2D polygon = new Path2D.Double(); - polygon.moveTo(0, 0); - polygon.lineTo(0, 500); - polygon.lineTo(300, 500); - polygon.lineTo(300, 0); - polygon.closePath(); - - Model copy = new SubModelCommand(model, polygon).execute(); - - CellDesignerXmlParser parser = new CellDesignerXmlParser(); - String xmlString = parser.toXml(copy); - - InputStream stream = new ByteArrayInputStream(xmlString.getBytes(StandardCharsets.UTF_8)); - - Model model2 = parser.createModel(new ConverterParams().inputStream(stream).sizeAutoAdjust(false)); - - ModelComparator mc = new ModelComparator(); - assertEquals(0, mc.compare(copy, model2)); - - } catch (Exception e) { - e.printStackTrace(); - throw e; - } - } + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testGetSubmodel1() throws Exception { + try { + Model model = getModelForFile("testFiles/spliting_test_Case.xml", true); + + Path2D polygon = new Path2D.Double(); + polygon.moveTo(0, 0); + polygon.lineTo(0, 100); + polygon.lineTo(100, 100); + polygon.lineTo(100, 0); + polygon.closePath(); + + Model copy = new SubModelCommand(model, polygon).execute(); + + assertEquals(2, copy.getElements().size()); + assertEquals(0, copy.getReactions().size()); + + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + + @Test + public void testGetSubmodel2() throws Exception { + try { + Model model = getModelForFile("testFiles/spliting_test_Case.xml", true); + + Path2D polygon = new Path2D.Double(); + polygon.moveTo(50, 50); + polygon.lineTo(350, 50); + polygon.lineTo(350, 200); + polygon.lineTo(50, 200); + polygon.closePath(); + + Model copy = new SubModelCommand(model, polygon).execute(); + + assertEquals(9, copy.getElements().size()); + assertEquals(1, copy.getReactions().size()); + + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + + @Test + public void testGetSubmodel3() throws Exception { + try { + Model model = getModelForFile("testFiles/spliting_test_Case.xml", true); + + Path2D polygon = new Path2D.Double(); + polygon.moveTo(0, 200); + polygon.lineTo(350, 200); + polygon.lineTo(350, 400); + polygon.lineTo(0, 400); + polygon.closePath(); + + Model copy = new SubModelCommand(model, polygon).execute(); + + double dx = 10; + double dy = -10; + + new MoveCommand(copy, dx, dy).execute(); + + assertEquals(model.getElementByElementId("sa3").getCenterX(), copy.getElementByElementId("sa3").getCenterX() - dx, + EPSILON); + assertEquals(model.getElementByElementId("sa3").getCenterY(), copy.getElementByElementId("sa3").getCenterY() - dy, + EPSILON); + + assertEquals(model.getReactionByReactionId("re3").getLines().get(0).getX2(), + copy.getReactionByReactionId("re3").getLines().get(0).getX2() - dx, EPSILON); + assertEquals(model.getReactionByReactionId("re3").getLines().get(0).getY2(), + copy.getReactionByReactionId("re3").getLines().get(0).getY2() - dy, EPSILON); + + CellDesignerXmlParser parser = new CellDesignerXmlParser(); + String xml = parser.toXml(copy); + + InputStream stream = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8)); + Model copy2 = parser.createModel(new ConverterParams().inputStream(stream).sizeAutoAdjust(false)); + ModelComparator comparator = new ModelComparator(); + + // check if after conversion to xml everything works + assertEquals(0, comparator.compare(copy, copy2)); + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + + @Test + public void testGetSubmodelWithoutCompartments() throws Exception { + try { + Model model = getModelForFile("testFiles/compartments.xml", true); + + Path2D polygon = new Path2D.Double(); + polygon.moveTo(0, 10); + polygon.lineTo(10, 10); + polygon.lineTo(10, 0); + polygon.lineTo(0, 0); + polygon.closePath(); + + Model copy = new SubModelCommand(model, polygon).execute(); + + // we should cut off some of compartmets + assertFalse(model.getLayers().iterator().next().getTexts().size() == copy.getLayers().iterator().next().getTexts() + .size()); + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + + @Test + public void testGetSubmodelWithoutCompartments2() throws Exception { + try { + Model model = getModelForFile("testFiles/problematic/cutting_without_compartment.xml", true); + + Path2D polygon = new Path2D.Double(); + polygon.moveTo(0, 0); + polygon.lineTo(0, 500); + polygon.lineTo(300, 500); + polygon.lineTo(300, 0); + polygon.closePath(); + + Model copy = new SubModelCommand(model, polygon).execute(); + + CellDesignerXmlParser parser = new CellDesignerXmlParser(); + String xmlString = parser.toXml(copy); + + InputStream stream = new ByteArrayInputStream(xmlString.getBytes(StandardCharsets.UTF_8)); + + Model model2 = parser.createModel(new ConverterParams().inputStream(stream).sizeAutoAdjust(false)); + + ModelComparator mc = new ModelComparator(); + assertEquals(0, mc.compare(copy, model2)); + + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + + @Test + public void testGetSubmodelWithElementIds() throws Exception { + try { + Model model = getModelForFile("testFiles/spliting_test_Case.xml", false); + + Path2D polygon = new Path2D.Double(); + polygon.moveTo(0, 0); + polygon.lineTo(0, 1000); + polygon.lineTo(1000, 1000); + polygon.lineTo(1000, 0); + polygon.closePath(); + model.getElementByElementId("sa2").setId(-2); + + Model copy = new SubModelCommand(model, polygon, new HashSet<>(Arrays.asList(-2)), new HashSet<>()).execute(); + + assertEquals(1, copy.getElements().size()); + assertEquals(0, copy.getReactions().size()); + + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + + @Test + public void testGetSubmodelWithEmptyElementIds() throws Exception { + try { + Model model = getModelForFile("testFiles/spliting_test_Case.xml", true); + + Path2D polygon = new Path2D.Double(); + polygon.moveTo(0, 0); + polygon.lineTo(0, 1000); + polygon.lineTo(1000, 1000); + polygon.lineTo(1000, 0); + polygon.closePath(); + + Model copy = new SubModelCommand(model, polygon, new HashSet<>(), new HashSet<>()).execute(); + + assertEquals(12, copy.getElements().size()); + assertEquals(3, copy.getReactions().size()); + + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + + @Test + public void testGetSubmodelWithReactionIds() throws Exception { + try { + Model model = getModelForFile("testFiles/spliting_test_Case.xml", false); + + Path2D polygon = new Path2D.Double(); + polygon.moveTo(0, 0); + polygon.lineTo(0, 1000); + polygon.lineTo(1000, 1000); + polygon.lineTo(1000, 0); + polygon.closePath(); + model.getReactions().iterator().next().setId(-2); + + Model copy = new SubModelCommand(model, polygon, new HashSet<>(), new HashSet<>(Arrays.asList(-2))).execute(); + + assertEquals(1, copy.getReactions().size()); + + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } } diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/ModelController.java b/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/ModelController.java index d350d59b6131c28a72bc47bb2f8ba281a0018a74..c72604753660d2bfb4462e08e3271b41e277a4a7 100644 --- a/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/ModelController.java +++ b/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/ModelController.java @@ -93,8 +93,8 @@ public class ModelController extends BaseController { .body(file.getFileContent()); } - @RequestMapping(value = "/projects/{projectId}/models/{modelId}:downloadModel", method = { - RequestMethod.GET }, produces = { MediaType.APPLICATION_JSON_VALUE }) + @RequestMapping(value = "/projects/{projectId}/models/{modelId}:downloadModel", method = { RequestMethod.GET, + RequestMethod.POST }, produces = { MediaType.APPLICATION_JSON_VALUE }) public ResponseEntity<byte[]> getModelAsModelFile(// @CookieValue(value = Configuration.AUTH_TOKEN) String token, // @PathVariable(value = "projectId") String projectId, // @@ -103,12 +103,14 @@ public class ModelController extends BaseController { @RequestParam(value = "backgroundOverlayId", defaultValue = "") String backgroundOverlayId, // @RequestParam(value = "overlayIds", defaultValue = "") String overlayIds, // @RequestParam(value = "zoomLevel", defaultValue = "") String zoomLevel, // - @RequestParam(value = "polygonString", defaultValue = "") String polygonString// + @RequestParam(value = "polygonString", defaultValue = "") String polygonString, // + @RequestParam(value = "elementIds", defaultValue = "") String elementIds, // + @RequestParam(value = "reactionIds", defaultValue = "") String reactionIds // ) throws SecurityException, QueryException, IOException, InvalidColorSchemaException, CommandExecutionException, ConverterException, InconsistentModelException { FileEntry file = modelController.getModelAsModelFile(token, projectId, modelId, handlerClass, backgroundOverlayId, - overlayIds, zoomLevel, polygonString); + overlayIds, zoomLevel, polygonString, elementIds, reactionIds); MediaType type = MediaType.APPLICATION_OCTET_STREAM; return ResponseEntity.ok().contentLength(file.getFileContent().length).contentType(type) .header("Content-Disposition", "attachment; filename=" + file.getOriginalFileName()) diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/ModelRestImpl.java b/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/ModelRestImpl.java index f735bb5937aa81e1c578ebfb0d15a1142caa8d6e..bf5adaf6922b73d6f059e71c5b02f80309e6466d 100644 --- a/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/ModelRestImpl.java +++ b/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/ModelRestImpl.java @@ -10,6 +10,7 @@ import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Collection; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -58,8 +59,6 @@ import lcsb.mapviewer.services.utils.data.BuildInLayout; @Transactional(value = "txManager") public class ModelRestImpl extends BaseRestImpl { - - /** * Constant defining size of the array returned by * {@link PathIterator#currentSegment(double[])} method. More information can be @@ -180,7 +179,6 @@ public class ModelRestImpl extends BaseRestImpl { } else { throw new InvalidArgumentException(); } - } private Double parseDouble(Object value) throws QueryException { @@ -206,37 +204,25 @@ public class ModelRestImpl extends BaseRestImpl { } public FileEntry getModelAsModelFile(String token, String projectId, String modelId, String handlerClass, - String backgroundOverlayId, String overlayIds, String zoomLevel, String polygonString) - throws SecurityException, QueryException, IOException, InvalidColorSchemaException, CommandExecutionException, - ConverterException, InconsistentModelException { + String backgroundOverlayId, String overlayIds, String zoomLevel, String polygonString, String elementIds, + String reactionIds) throws SecurityException, QueryException, IOException, InvalidColorSchemaException, + CommandExecutionException, ConverterException, InconsistentModelException { User user = getUserService().getUserByToken(token); - Model topModel = getModelService().getLastModelByProjectId(projectId, token); - if (topModel == null) { - throw new ObjectNotFoundException("Project with given id doesn't exist"); - } - - Model originalModel = topModel.getSubmodelById(modelId); - - if (originalModel == null) { - throw new ObjectNotFoundException("Model with given id doesn't exist"); - } + Model originalModel = getModelByModelId(token, projectId, modelId); Path2D polygon = stringToPolygon(polygonString, originalModel); + Set<Integer> elementIdsList = stringListToIntegerSet(elementIds); + Set<Integer> reactionIdsList = stringListToIntegerSet(reactionIds); + // create model bounded by the polygon - SubModelCommand subModelCommand = new SubModelCommand(originalModel, polygon); + SubModelCommand subModelCommand = new SubModelCommand(originalModel, polygon, elementIdsList, reactionIdsList); Model part = subModelCommand.execute(); // Get list of overlay ids - String[] overlayIdsList; - if (overlayIds == null || overlayIds.trim().isEmpty()) { - overlayIdsList = new String[0]; - } else { - overlayIdsList = overlayIds.split(","); - } + String[] overlayIdsList = stringListToArray(overlayIds); // Remove all colors if (overlayIdsList.length > 0) { - for (Element element : part.getElements()) { element.setColor(Color.WHITE); } @@ -264,6 +250,43 @@ public class ModelRestImpl extends BaseRestImpl { } + protected Set<Integer> stringListToIntegerSet(String elementIds) { + Set<Integer> result = new HashSet<>(); + if (elementIds != null) { + String[] stringIds = elementIds.split(","); + for (String string : stringIds) { + if (!string.trim().isEmpty()) { + result.add(Integer.valueOf(string)); + } + } + } + return result; + } + + private Model getModelByModelId(String token, String projectId, String modelId) + throws SecurityException, ObjectNotFoundException { + Model topModel = getModelService().getLastModelByProjectId(projectId, token); + if (topModel == null) { + throw new ObjectNotFoundException("Project with given id doesn't exist"); + } + + Model originalModel = topModel.getSubmodelById(modelId); + + if (originalModel == null) { + throw new ObjectNotFoundException("Model with given id doesn't exist"); + } + return originalModel; + } + + private String[] stringListToArray(String overlayIds) { + String[] overlayIdsList; + if (overlayIds == null || overlayIds.trim().isEmpty()) { + overlayIdsList = new String[0]; + } else { + overlayIdsList = overlayIds.split(","); + } + return overlayIdsList; + } public FileEntry getModelAsImage(String token, String projectId, String modelId, String handlerClass, String backgroundOverlayId, String overlayIds, String zoomLevel, String polygonString) throws SecurityException, @@ -424,5 +447,4 @@ public class ModelRestImpl extends BaseRestImpl { return result; } - } diff --git a/rest-api/src/test/java/lcsb/mapviewer/api/projects/models/ModelRestImplTest.java b/rest-api/src/test/java/lcsb/mapviewer/api/projects/models/ModelRestImplTest.java index 75e4f09a45a7bffdb355311eaf3b0e8891a6f6e1..80fe6f15bc32b675e78678324bae8452893aef32 100644 --- a/rest-api/src/test/java/lcsb/mapviewer/api/projects/models/ModelRestImplTest.java +++ b/rest-api/src/test/java/lcsb/mapviewer/api/projects/models/ModelRestImplTest.java @@ -9,6 +9,7 @@ import static org.mockito.ArgumentMatchers.refEq; import java.util.List; import java.util.Map; +import java.util.Set; import org.junit.After; import org.junit.Before; @@ -117,8 +118,8 @@ public class ModelRestImplTest extends RestTestFunctions { public void testGetModelAsImage() throws Exception { try { ModelRestImpl modelRest = createMockProjectRest("testFiles/model/sample.xml"); - FileEntry result = modelRest.getModelAsImage(token, "sample", "0", PdfImageGenerator.class.getCanonicalName(), - "", "", "", ""); + FileEntry result = modelRest.getModelAsImage(token, "sample", "0", PdfImageGenerator.class.getCanonicalName(), "", + "", "", ""); assertNotNull(result); } catch (Exception e) { e.printStackTrace(); @@ -141,7 +142,7 @@ public class ModelRestImplTest extends RestTestFunctions { public void testGetModelAsFileModel() throws Exception { try { ModelRestImpl modelRest = createMockProjectRest("testFiles/model/sample.xml"); - modelRest.getModelAsModelFile(token, "sample", "0", "", "", "", "", ""); + modelRest.getModelAsModelFile(token, "sample", "0", "", "", "", "", "", null, null); fail("Exception expected"); } catch (QueryException e) { } catch (Exception e) { @@ -155,7 +156,7 @@ public class ModelRestImplTest extends RestTestFunctions { try { ModelRestImpl modelRest = createMockProjectRest("testFiles/model/sample.xml"); modelRest.getModelAsModelFile(token, "sample", "0", CellDesignerXmlParser.class.getCanonicalName(), "", "", "", - "0,0;90,0;90,90;90,0"); + "0,0;90,0;90,90;90,0", null, null); } catch (Exception e) { e.printStackTrace(); throw e; @@ -166,7 +167,7 @@ public class ModelRestImplTest extends RestTestFunctions { public void testGetModelAsFileModel3() throws Exception { try { ModelRestImpl modelRest = createMockProjectRest("testFiles/model/sample.xml"); - modelRest.getModelAsModelFile(token, "sample", "0", "", "", "", "", "0,0;90,0;90,90;90,0"); + modelRest.getModelAsModelFile(token, "sample", "0", "", "", "", "", "0,0;90,0;90,90;90,0", null, null); fail("Exception expected"); } catch (QueryException e) { } catch (Exception e) { @@ -175,5 +176,26 @@ public class ModelRestImplTest extends RestTestFunctions { } } - + @Test + public void testEmptyStringListToIntegerList() throws Exception { + try { + Set<Integer> ids = _modelRestImpl.stringListToIntegerSet(""); + assertNotNull(ids); + assertEquals(0, ids.size()); + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + @Test + public void testStringListToIntegerArray() throws Exception { + try { + Set<Integer> ids = _modelRestImpl.stringListToIntegerSet("12,3"); + assertNotNull(ids); + assertEquals(2, ids.size()); + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } }