diff --git a/frontend-js/src/main/js/ServerConnector.js b/frontend-js/src/main/js/ServerConnector.js index ae6de2653f56a887a2917c84be3e55616535e267..01b15bbea04f35ae7e9b73a9cf86eb5da8760bf3 100644 --- a/frontend-js/src/main/js/ServerConnector.js +++ b/frontend-js/src/main/js/ServerConnector.js @@ -1937,6 +1937,20 @@ ServerConnector.getImageDownloadUrl = function (params) { }); }; +/** + * + * @param {Object} params + * @param {string} [params.projectId] + * @param {number} params.modelId + * @param {string} [params.polygonString] + * @param {string} params.handlerClass + * @param {number} [params.backgroundOverlayId] + * @param {number} [params.zoomLevel] + * @param {number[]} [params.overlayIds] + * @param {number[]} [params.elementIds] + * @param {number[]} [params.reactionIds] + * @returns {Promise} + */ ServerConnector.getModelDownloadUrl = function (params) { var self = this; var queryParams = { @@ -1944,12 +1958,13 @@ ServerConnector.getModelDownloadUrl = function (params) { modelId: params.modelId }; var filterParams = { - token: params.token, polygonString: params.polygonString, handlerClass: params.handlerClass, backgroundOverlayId: params.backgroundOverlayId, zoomLevel: params.zoomLevel, - overlayIds: this.idsToString(params.overlayIds) + overlayIds: this.idsToString(params.overlayIds), + elementIds: this.idsToString(params.elementIds), + reactionIds: this.idsToString(params.reactionIds) }; return self.getProjectId(params.projectId).then(function (result) { queryParams.projectId = result; @@ -1957,6 +1972,41 @@ ServerConnector.getModelDownloadUrl = function (params) { }); }; +/** + * + * @param {Object} params + * @param {string} [params.projectId] + * @param {number} params.modelId + * @param {string} [params.polygonString] + * @param {string} params.handlerClass + * @param {number} [params.backgroundOverlayId] + * @param {number} [params.zoomLevel] + * @param {number[]} [params.overlayIds] + * @param {number[]} [params.elementIds] + * @param {number[]} [params.reactionIds] + * @returns {Promise} + */ +ServerConnector.getPartOfModelInExportFormat = function (params) { + var self = this; + var queryParams = { + projectId: params.projectId, + modelId: params.modelId + }; + var filterParams = { + polygonString: params.polygonString, + handlerClass: params.handlerClass, + backgroundOverlayId: params.backgroundOverlayId, + zoomLevel: params.zoomLevel, + overlayIds: this.idsToString(params.overlayIds), + elementIds: this.idsToString(params.elementIds), + reactionIds: this.idsToString(params.reactionIds) + }; + return self.getProjectId(params.projectId).then(function (result) { + queryParams.projectId = result; + return self.sendPostRequest(self.getModelPartUrl(queryParams), filterParams); + }); +}; + ServerConnector.getImageConverters = function () { var self = this; return self.getConfiguration().then(function (configuration) { diff --git a/frontend-js/src/main/js/plugin/MinervaPluginProxy.js b/frontend-js/src/main/js/plugin/MinervaPluginProxy.js index 6a30568a937a07888ecc4bd7b106fbfde43e8a02..15fbc9e6587bbb7ce763ac7e7200e7bfbd206cf5 100644 --- a/frontend-js/src/main/js/plugin/MinervaPluginProxy.js +++ b/frontend-js/src/main/js/plugin/MinervaPluginProxy.js @@ -137,6 +137,38 @@ function createProjectData(options) { } }); }, + /** + * Export part of the map that includes bioEntities into a known format. + * + * @param {Object} param + * @param {string} param.handlerClass format defined in {Configuration#getModelConverters} + * @param {number} param.modelId id of the model + * @param {Array} param.bioEntities + * @returns {Promise} + */ + exportToMapFormat: function (param) { + var exportParams = { + projectId: map.getProject().getProjectId(), + modelId: param.modelId, + handlerClass: param.handlerClass, + elementIds: [], + reactionIds: [] + }; + for (var i = 0; i < param.bioEntities.length; i++) { + var ie = new IdentifiedElement(param.bioEntities[i]); + if (ie.getType() === "ALIAS") { + exportParams.elementIds.push(ie.getId()); + } else if (ie.getType() === "REACTION") { + exportParams.reactionIds.push(ie.getId()); + } else { + return Promise.reject(new Error("Unsupported bioentity type: " + ie.getType())); + } + if (ie.getModelId() !== param.modelId) { + return Promise.reject(new Error("Export of bioEntities from few maps is not supported. ModelId: " + param.modelId + "; element modelId: " + ie.getModelId())); + } + } + return options.map.getServerConnector().getPartOfModelInExportFormat(exportParams); + }, getAllBioEntities: function () { var models = map.getProject().getModels(); var result = []; @@ -312,7 +344,7 @@ function createWrapperFunctionForDialogGuiUpdate(param) { * @param {CustomMap} options.map * @param {Plugin} options.plugin * @param {string} options.pluginId - * @returns {{getVisibleDataOverlays: function(): (Promise<DataOverlay[]>|*), addListener: addListener, removeListener: removeListener, removeAllListeners: function(): Array, getHighlightedBioEntities: function(*=): *, showBioEntity: function(*=): *, hideBioEntity: function(*=): Promise<T>, setCenter: function(*): PromiseLike, getCenter: function(*): Point, getBounds: function(*): Bounds, fitBounds: function(*): void, setZoom: function(*): *, getZoom: function(*): number, openMap: function(*): PromiseLike}} + * @returns {{getVisibleDataOverlays: (function(): (Promise<DataOverlay[]>|*)), addListener: addListener, removeListener: removeListener, removeAllListeners: (function(): Array), getHighlightedBioEntities: (function(*=): Promise<Array | never>), showBioEntity: (function(*=): *), hideBioEntity: (function(*=): Promise<any | never>), setCenter: (function(*): PromiseLike), getCenter: (function(*): Point), getBounds: (function(*): Bounds), fitBounds: (function(*): void), setZoom: (function(*): *), getZoom: (function(*): number), openMap: (function(*): PromiseLike)}} */ function createProjectMap(options) { var map = options.map; @@ -569,7 +601,7 @@ function createProjectMap(options) { * @param {CustomMap} options.map * @param {Plugin} options.plugin * @param {string} options.pluginId - * @returns {{data: {getBioEntityById: function(*=): Promise<any>, getAllBioEntities: function(): *, getReactionsWithElement: function(*=): *, getProjectId: function(): string, getName: function(): string, getVersion: function(): string, getDisease: getDisease, getOrganism: getOrganism, getModels: function(): *[]}, map: {getVisibleDataOverlays: function(): (Promise<DataOverlay[]>|*), addListener: addListener, removeListener: removeListener, removeAllListeners: function(): Array, getHighlightedBioEntities: function(*=): *, showBioEntity: function(*=): *, hideBioEntity: function(*=): Promise<T>, setCenter: function(*): PromiseLike, getCenter: function(*): Point, getBounds: function(*): Bounds, fitBounds: function(*): void, setZoom: function(*): *, getZoom: function(*): number, openMap: function(*): PromiseLike}}} + * @returns {{data: {getBioEntityById: (function(*=): Promise<any>), getAllBioEntities: (function(): *), getReactionsWithElement: (function(*=): *), getProjectId: (function(): string), getName: (function(): string), getVersion: (function(): string), getDisease: getDisease, getOrganism: getOrganism, getModels: (function(): *[])}, map: {getVisibleDataOverlays: (function(): (Promise<DataOverlay[]>|*)), addListener: addListener, removeListener: removeListener, removeAllListeners: (function(): Array), getHighlightedBioEntities: (function(*=): Promise<Array|never>), showBioEntity: (function(*=): *), hideBioEntity: (function(*=): Promise<any|never>), setCenter: (function(*): PromiseLike), getCenter: (function(*): Point), getBounds: (function(*): Bounds), fitBounds: (function(*): void), setZoom: (function(*): *), getZoom: (function(*): number), openMap: (function(*): PromiseLike)}}} */ function createProject(options) { return { @@ -635,17 +667,16 @@ function createPluginData(options) { * @param {HTMLElement} options.element * @param {Configuration} options.configuration * @param {ServerConnector} options.serverConnector - * @returns {{pluginId: string|string, element: *, project: {data: {getBioEntityById: function(*=): Promise<any>, getAllBioEntities: function(): *, getReactionsWithElement: function(*=): *, getProjectId: function(): string, getName: function(): string, getVersion: function(): string, getDisease: getDisease, getOrganism: getOrganism, getModels: function(): *[]}, map: {getVisibleDataOverlays: function(): (Promise<DataOverlay[]>|*), addListener: addListener, removeListener: removeListener, removeAllListeners: function(): Array, getHighlightedBioEntities: function(*=): *, showBioEntity: function(*=): *, hideBioEntity: function(*=): Promise<T>, setCenter: function(*): PromiseLike, getCenter: function(*): Point, getBounds: function(*): Bounds, fitBounds: function(*): void, setZoom: function(*): *, getZoom: function(*): number, openMap: function(*): PromiseLike}}, configuration: {options: ConfigurationOption[], overlayTypes: string[], imageConverters: ImageConverter[], modelConverters: ModelConverter[], elementTypes: BioEntityType[], reactionTypes: BioEntityType[], miriamTypes: MiriamType[], mapTypes: MapType[], modificationStateTypes: ModificationStateType[], privilegeTypes: PrivilegeType[], annotators: Annotator[]}, pluginData: {setGlobalParam: function(*=, *=): *, getGlobalParam: function(*=): *, setUserParam: function(*=, *=): *, getUserParam: function(*=): *}}} + * @returns {{pluginId: (string|string), element: HTMLElement, project: {data: {getBioEntityById: (function(*=): Promise<any>), getAllBioEntities: (function(): *), getReactionsWithElement: (function(*=): *), getProjectId: (function(): string), getName: (function(): string), getVersion: (function(): string), getDisease: getDisease, getOrganism: getOrganism, getModels: (function(): *[])}, map: {getVisibleDataOverlays: (function(): (Promise<DataOverlay[]>|*)), addListener: addListener, removeListener: removeListener, removeAllListeners: (function(): Array), getHighlightedBioEntities: (function(*=): Promise<Array|never>), showBioEntity: (function(*=): *), hideBioEntity: (function(*=): Promise<any|never>), setCenter: (function(*): PromiseLike), getCenter: (function(*): Point), getBounds: (function(*): Bounds), fitBounds: (function(*): void), setZoom: (function(*): *), getZoom: (function(*): number), openMap: (function(*): PromiseLike)}}, configuration: {options: ConfigurationOption[], overlayTypes: string[], imageConverters: ImageConverter[], modelConverters: ModelConverter[], elementTypes: BioEntityType[], reactionTypes: BioEntityType[], miriamTypes: MiriamType[], mapTypes: MapType[], modificationStateTypes: ModificationStateType[], privilegeTypes: PrivilegeType[], annotators: Annotator[]}, pluginData: {setGlobalParam: (function(*=, *=): *), getGlobalParam: (function(*=): *), setUserParam: (function(*=, *=): *), getUserParam: (function(*=): *)}}} * @constructor */ function MinervaPluginProxy(options) { - return { - pluginId: options.pluginId, - element: options.element, - project: createProject(options), - configuration: createConfiguration(options), - pluginData: createPluginData(options) - }; + this.pluginId = options.pluginId; + this.element = options.element; + this.project = createProject(options); + this.configuration = createConfiguration(options); + this.pluginData = createPluginData(options); + } module.exports = MinervaPluginProxy; diff --git a/frontend-js/src/test/js/plugin/MinervaPluginProxy-test.js b/frontend-js/src/test/js/plugin/MinervaPluginProxy-test.js index 4715ed3b0fed6036022550d246f856fe9a689e75..116e8d8537e7e2190081c191c07ee9c6a2910d54 100644 --- a/frontend-js/src/test/js/plugin/MinervaPluginProxy-test.js +++ b/frontend-js/src/test/js/plugin/MinervaPluginProxy-test.js @@ -181,10 +181,10 @@ describe('MinervaPluginProxy', function () { describe("getBioEntityById", function () { it("for alias", function () { - var map, proxy; + var map; return ServerConnector.getProject().then(function (project) { map = helper.createCustomMap(project); - proxy = createProxy(map); + var proxy = createProxy(map); return proxy.project.data.getBioEntityById({ id: 329177, modelId: 15781, @@ -198,10 +198,10 @@ describe('MinervaPluginProxy', function () { }); it("for reaction", function () { - var map, proxy; + var map; return ServerConnector.getProject().then(function (project) { map = helper.createCustomMap(project); - proxy = createProxy(map); + var proxy = createProxy(map); return proxy.project.data.getBioEntityById({ id: 153508, modelId: 15781, @@ -216,6 +216,26 @@ describe('MinervaPluginProxy', function () { }); }); + describe("exportToMapFormat", function () { + it("for alias", function () { + var map; + return ServerConnector.getProject().then(function (project) { + map = helper.createCustomMap(project); + var proxy = createProxy(map); + return proxy.project.data.exportToMapFormat({ + modelId: 15781, + bioEntities: [{id: 329177, modelId: 15781, type: "ALIAS"}], + handlerClass: helper.getConfiguration().getModelConverters()[0].handler + }); + }).then(function (result) { + assert.ok(result); + }).then(function () { + map.destroy(); + }); + }); + + }); + describe("showElement", function () { it("alias", function () { var elementToShow = { @@ -238,7 +258,8 @@ describe('MinervaPluginProxy', function () { color: "#FF0000" } }; - var map, proxy; + var map; + var proxy; return ServerConnector.getProject().then(function (project) { map = helper.createCustomMap(project); proxy = createProxy(map); diff --git a/frontend-js/testFiles/apiCalls/projects/sample/models/15781.downloadModel/POST_elementIds=329177&handlerClass=lcsb.mapviewer.converter.model.celldesigner.CellDesignerXmlParser&token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/projects/sample/models/15781.downloadModel/POST_elementIds=329177&handlerClass=lcsb.mapviewer.converter.model.celldesigner.CellDesignerXmlParser&token=MOCK_TOKEN_ID& new file mode 100644 index 0000000000000000000000000000000000000000..c83f0983baeb47529744650af680789d24fa844e --- /dev/null +++ b/frontend-js/testFiles/apiCalls/projects/sample/models/15781.downloadModel/POST_elementIds=329177&handlerClass=lcsb.mapviewer.converter.model.celldesigner.CellDesignerXmlParser&token=MOCK_TOKEN_ID& @@ -0,0 +1,63 @@ +<?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="untitled" id="untitled"> +<listOfUnitDefinitions> +</listOfUnitDefinitions> +<listOfFunctionDefinitions> +</listOfFunctionDefinitions> +<annotation> +<celldesigner:extension> +<celldesigner:modelVersion>4.0</celldesigner:modelVersion> +<celldesigner:modelDisplay sizeX="1305" sizeY="473"/> +<celldesigner:listOfIncludedSpecies> +</celldesigner:listOfIncludedSpecies> +<celldesigner:listOfCompartmentAliases> +</celldesigner:listOfCompartmentAliases> +<celldesigner:listOfComplexSpeciesAliases> +</celldesigner:listOfComplexSpeciesAliases> +<celldesigner:listOfSpeciesAliases> +<celldesigner:speciesAlias id="sa10" species="s_id_sa10" > +<celldesigner:activity>inactive</celldesigner:activity> +<celldesigner:bounds x="0.0" y="186.0" w="80.0" h="30.0" /> +<celldesigner:font size="12.0"/> +<celldesigner:view state="usual"/> +<celldesigner:usualView><celldesigner:innerPosition x="0.0" y="186.0"/><celldesigner:boxSize width="80.0" height="30.0"/><celldesigner:singleLine width="1.0"/><celldesigner:paint color="FFFF00FF" scheme="Color"/></celldesigner:usualView> +<celldesigner:briefView><celldesigner:innerPosition x="0.0" y="186.0"/><celldesigner:boxSize width="80.0" height="30.0"/><celldesigner:singleLine width="1.0"/><celldesigner:paint color="FFFF00FF" scheme="Color"/></celldesigner:briefView> +</celldesigner:speciesAlias> +</celldesigner:listOfSpeciesAliases> +<celldesigner:listOfProteins></celldesigner:listOfProteins> +<celldesigner:listOfGenes></celldesigner:listOfGenes> +<celldesigner:listOfRNAs></celldesigner:listOfRNAs> +<celldesigner:listOfAntisenseRNAs></celldesigner:listOfAntisenseRNAs> +<celldesigner:listOfLayers></celldesigner:listOfLayers> +</celldesigner:extension> +</annotation> +<listOfCompartments> +<compartment metaid="default" id="default" name="" size="1" units="volume" > +<annotation> +<celldesigner:extension> +<celldesigner:name></celldesigner:name> +</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="#"> +</rdf:Description> +</rdf:RDF> +</annotation> +<notes><html xmlns="http://www.w3.org/1999/xhtml"><head><title/></head><body> +</body></html></notes> +</compartment> +</listOfCompartments> +<listOfSpecies><species name="s10" id="s_id_sa10" metaid="s_id_sa10" initialAmount="0.0" compartment="default"><annotation><celldesigner:extension><celldesigner:positionToCompartment>inside</celldesigner:positionToCompartment><celldesigner:speciesIdentity><celldesigner:class>DRUG</celldesigner:class> +<celldesigner:name>s10</celldesigner:name> +</celldesigner:speciesIdentity> +</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="#"> +</rdf:Description> +</rdf:RDF> +</annotation> +</species> +</listOfSpecies> +<listOfReactions> +</listOfReactions> +<notes></notes></model></sbml> \ No newline at end of file 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/ProjectController.java b/rest-api/src/main/java/lcsb/mapviewer/api/projects/ProjectController.java index c2171f9fb93d19d327cf7e73f3fde0e92724ce88..974a5950987f032f73315b455f72e281681ed551 100644 --- a/rest-api/src/main/java/lcsb/mapviewer/api/projects/ProjectController.java +++ b/rest-api/src/main/java/lcsb/mapviewer/api/projects/ProjectController.java @@ -22,13 +22,8 @@ import org.springframework.web.bind.annotation.RestController; import lcsb.mapviewer.api.BaseController; import lcsb.mapviewer.api.ObjectNotFoundException; import lcsb.mapviewer.api.QueryException; -import lcsb.mapviewer.commands.CommandExecutionException; import lcsb.mapviewer.common.Configuration; -import lcsb.mapviewer.converter.ConverterException; -import lcsb.mapviewer.converter.graphics.DrawingException; import lcsb.mapviewer.model.cache.FileEntry; -import lcsb.mapviewer.model.map.InconsistentModelException; -import lcsb.mapviewer.model.map.layout.InvalidColorSchemaException; import lcsb.mapviewer.services.SecurityException; @RestController @@ -120,50 +115,6 @@ public class ProjectController extends BaseController { .body(file.getFileContent()); } - @RequestMapping(value = "/projects/{projectId}/models/{modelId}:downloadImage", method = { - RequestMethod.GET }, produces = { MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity<byte[]> getModelAsImage(// - @CookieValue(value = Configuration.AUTH_TOKEN) String token, // - @PathVariable(value = "projectId") String projectId, // - @PathVariable(value = "modelId") String modelId, // - @RequestParam(value = "handlerClass") String handlerClass, // - @RequestParam(value = "backgroundOverlayId", defaultValue = "") String backgroundOverlayId, // - @RequestParam(value = "overlayIds", defaultValue = "") String overlayIds, // - @RequestParam(value = "zoomLevel", defaultValue = "") String zoomLevel, // - @RequestParam(value = "polygonString", defaultValue = "") String polygonString// - ) throws SecurityException, QueryException, IOException, InvalidColorSchemaException, CommandExecutionException, - DrawingException { - - FileEntry file = projectController.getModelAsImage(token, projectId, modelId, handlerClass, backgroundOverlayId, - overlayIds, zoomLevel, polygonString); - MediaType type = MediaType.APPLICATION_OCTET_STREAM; - return ResponseEntity.ok().contentLength(file.getFileContent().length).contentType(type) - .header("Content-Disposition", "attachment; filename=" + file.getOriginalFileName()) - .body(file.getFileContent()); - } - - @RequestMapping(value = "/projects/{projectId}/models/{modelId}:downloadModel", method = { - RequestMethod.GET }, produces = { MediaType.APPLICATION_JSON_VALUE }) - public ResponseEntity<byte[]> getModelAsModelFile(// - @CookieValue(value = Configuration.AUTH_TOKEN) String token, // - @PathVariable(value = "projectId") String projectId, // - @PathVariable(value = "modelId") String modelId, // - @RequestParam(value = "handlerClass") String handlerClass, // - @RequestParam(value = "backgroundOverlayId", defaultValue = "") String backgroundOverlayId, // - @RequestParam(value = "overlayIds", defaultValue = "") String overlayIds, // - @RequestParam(value = "zoomLevel", defaultValue = "") String zoomLevel, // - @RequestParam(value = "polygonString", defaultValue = "") String polygonString// - ) throws SecurityException, QueryException, IOException, InvalidColorSchemaException, CommandExecutionException, - ConverterException, InconsistentModelException { - - FileEntry file = projectController.getModelAsModelFile(token, projectId, modelId, handlerClass, backgroundOverlayId, - overlayIds, zoomLevel, polygonString); - MediaType type = MediaType.APPLICATION_OCTET_STREAM; - return ResponseEntity.ok().contentLength(file.getFileContent().length).contentType(type) - .header("Content-Disposition", "attachment; filename=" + file.getOriginalFileName()) - .body(file.getFileContent()); - } - @RequestMapping(value = "/projects/{projectId}/logs/", method = { RequestMethod.GET }, produces = { MediaType.APPLICATION_JSON_VALUE }) public Map<String, Object> getLogs(// diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/projects/ProjectRestImpl.java b/rest-api/src/main/java/lcsb/mapviewer/api/projects/ProjectRestImpl.java index b0d4cee6b5a1daaa65835f322cb113bcb8e89719..528c189b5d01beacf58f447900357a3f34efa075 100644 --- a/rest-api/src/main/java/lcsb/mapviewer/api/projects/ProjectRestImpl.java +++ b/rest-api/src/main/java/lcsb/mapviewer/api/projects/ProjectRestImpl.java @@ -1,19 +1,12 @@ package lcsb.mapviewer.api.projects; -import java.awt.Color; -import java.awt.geom.Path2D; -import java.awt.geom.PathIterator; import java.awt.geom.Point2D; import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileInputStream; import java.io.IOException; -import java.io.InputStream; import java.io.Serializable; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; -import java.util.Collection; import java.util.Comparator; import java.util.HashSet; import java.util.LinkedHashMap; @@ -22,7 +15,6 @@ import java.util.Map; import java.util.Set; import java.util.TreeMap; -import org.apache.commons.io.IOUtils; import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; @@ -34,21 +26,9 @@ import lcsb.mapviewer.api.ObjectNotFoundException; import lcsb.mapviewer.api.OperationNotAllowedException; import lcsb.mapviewer.api.QueryException; import lcsb.mapviewer.api.projects.models.publications.PublicationsRestImpl; -import lcsb.mapviewer.commands.ClearColorModelCommand; -import lcsb.mapviewer.commands.ColorExtractor; -import lcsb.mapviewer.commands.ColorModelCommand; -import lcsb.mapviewer.commands.CommandExecutionException; -import lcsb.mapviewer.commands.CopyCommand; -import lcsb.mapviewer.commands.SetFixedHierarchyLevelCommand; -import lcsb.mapviewer.commands.SubModelCommand; -import lcsb.mapviewer.common.Configuration; import lcsb.mapviewer.common.exception.InvalidArgumentException; import lcsb.mapviewer.common.exception.NotImplementedException; -import lcsb.mapviewer.converter.ConverterException; import lcsb.mapviewer.converter.IConverter; -import lcsb.mapviewer.converter.graphics.AbstractImageGenerator.Params; -import lcsb.mapviewer.converter.graphics.DrawingException; -import lcsb.mapviewer.converter.graphics.ImageGenerators; import lcsb.mapviewer.converter.zip.ImageZipEntryFile; import lcsb.mapviewer.converter.zip.LayoutZipEntryFile; import lcsb.mapviewer.converter.zip.ModelZipEntryFile; @@ -58,7 +38,6 @@ import lcsb.mapviewer.model.cache.FileEntry; import lcsb.mapviewer.model.cache.UploadedFileEntry; import lcsb.mapviewer.model.graphics.MapCanvasType; import lcsb.mapviewer.model.map.BioEntity; -import lcsb.mapviewer.model.map.InconsistentModelException; import lcsb.mapviewer.model.map.MiriamData; import lcsb.mapviewer.model.map.MiriamType; import lcsb.mapviewer.model.map.OverviewImage; @@ -66,9 +45,6 @@ import lcsb.mapviewer.model.map.OverviewImageLink; import lcsb.mapviewer.model.map.OverviewLink; import lcsb.mapviewer.model.map.OverviewModelLink; import lcsb.mapviewer.model.map.OverviewSearchLink; -import lcsb.mapviewer.model.map.layout.ColorSchema; -import lcsb.mapviewer.model.map.layout.InvalidColorSchemaException; -import lcsb.mapviewer.model.map.layout.Layout; import lcsb.mapviewer.model.map.model.Model; import lcsb.mapviewer.model.map.model.SubmodelType; import lcsb.mapviewer.model.map.reaction.Reaction; @@ -79,24 +55,12 @@ import lcsb.mapviewer.model.user.User; import lcsb.mapviewer.persist.dao.ProjectDao; import lcsb.mapviewer.persist.dao.cache.UploadedFileEntryDao; import lcsb.mapviewer.services.SecurityException; -import lcsb.mapviewer.services.interfaces.ILayoutService; import lcsb.mapviewer.services.interfaces.IProjectService; -import lcsb.mapviewer.services.utils.ColorSchemaReader; import lcsb.mapviewer.services.utils.CreateProjectParams; -import lcsb.mapviewer.services.utils.data.BuildInLayout; @Transactional(value = "txManager") public class ProjectRestImpl extends BaseRestImpl { - /** - * Constant defining size of the array returned by - * {@link PathIterator#currentSegment(double[])} method. More information can be - * found <a href= - * "http://docs.oracle.com/javase/7/docs/api/java/awt/geom/PathIterator.html#currentSegment(double[])" - * >here</a> - */ - private static final int PATH_ITERATOR_SEGMENT_SIZE = 6; - /** * Default class logger. */ @@ -105,9 +69,6 @@ public class ProjectRestImpl extends BaseRestImpl { @Autowired private PublicationsRestImpl publicationsRestImpl; - @Autowired - private ILayoutService layoutService; - @Autowired private IProjectService projectService; @@ -240,224 +201,6 @@ public class ProjectRestImpl extends BaseRestImpl { return project.getInputData(); } - public FileEntry getModelAsImage(String token, String projectId, String modelId, String handlerClass, - String backgroundOverlayId, String overlayIds, String zoomLevel, String polygonString) throws SecurityException, - QueryException, IOException, InvalidColorSchemaException, CommandExecutionException, DrawingException { - 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"); - } - - Layout overlay = null; - if (!backgroundOverlayId.equals("")) { - overlay = topModel.getLayoutByIdentifier(Integer.valueOf(backgroundOverlayId)); - - if (overlay == null) { - throw new ObjectNotFoundException("Unknown overlay in model. Layout.id=" + backgroundOverlayId); - } - } else { - if (topModel.getLayouts().size() > 0) { - overlay = topModel.getLayouts().get(0); - } - } - - Model colorModel = new CopyCommand(originalModel).execute(); - if (overlay != null) { - if (overlay.getInputData() != null) { - ColorSchemaReader reader = new ColorSchemaReader(); - Collection<ColorSchema> schemas = reader.readColorSchema(overlay.getInputData().getFileContent()); - - new ColorModelCommand(colorModel, schemas, getUserService().getColorExtractorForUser(user)).execute(); - } else if (overlay.getTitle().equals(BuildInLayout.CLEAN.getTitle())) { - // this might not return true if we change CLEAN.title in future... - - // if it's clean then remove coloring - new ClearColorModelCommand(colorModel).execute(); - } else if (overlay.isHierarchicalView()) { - new SetFixedHierarchyLevelCommand(colorModel, overlay.getHierarchyViewLevel()).execute(); - } - } - - Integer level = Configuration.MIN_ZOOM_LEVEL; - if (!zoomLevel.equals("")) { - level = Integer.valueOf(zoomLevel); - } - - Path2D polygon = stringToPolygon(polygonString, colorModel); - - Double minX = originalModel.getWidth(); - Double minY = originalModel.getHeight(); - Double maxX = 0.0; - Double maxY = 0.0; - - PathIterator pathIter = polygon.getPathIterator(null); - while (!pathIter.isDone()) { - final double[] segment = new double[PATH_ITERATOR_SEGMENT_SIZE]; - if (pathIter.currentSegment(segment) != PathIterator.SEG_CLOSE) { - minX = Math.min(minX, segment[0]); - maxX = Math.max(maxX, segment[0]); - minY = Math.min(minY, segment[1]); - maxY = Math.max(maxY, segment[1]); - } - pathIter.next(); - } - - maxX = Math.min(originalModel.getWidth(), maxX); - maxY = Math.min(originalModel.getHeight(), maxY); - minX = Math.max(0.0, minX); - minY = Math.max(0.0, minY); - - Double scale = Math.max(originalModel.getHeight(), originalModel.getWidth()) / (originalModel.getTileSize()); - - for (int i = level; i > Configuration.MIN_ZOOM_LEVEL; i--) { - scale /= 2; - } - - ColorExtractor colorExtractor = getUserService().getColorExtractorForUser(user); - - Params params = new Params().// - x(minX).// - y(minY).// - height((maxY - minY) / scale).// - width((maxX - minX) / scale).// - level(level - Configuration.MIN_ZOOM_LEVEL).// - nested(false).// automatically set nested view as invalid - scale(scale).// - colorExtractor(colorExtractor).// - sbgn(topModel.getProject().isSbgnFormat()).// - model(colorModel); - if (overlay != null) { - params.nested(overlay.isHierarchicalView()); - } - List<Integer> visibleLayoutIds = deserializeIdList(overlayIds); - for (Integer integer : visibleLayoutIds) { - Map<Object, ColorSchema> map = layoutService.getElementsForLayout(colorModel, integer, token); - params.addVisibleLayout(map); - } - - ImageGenerators imageGenerator = new ImageGenerators(); - String extension = imageGenerator.getExtension(handlerClass); - File file = File.createTempFile("map", "." + extension); - - imageGenerator.generate(handlerClass, params, file.getAbsolutePath()); - - UploadedFileEntry entry = new UploadedFileEntry(); - entry.setOriginalFileName("map." + extension); - entry.setFileContent(IOUtils.toByteArray(new FileInputStream(file))); - entry.setLength(entry.getFileContent().length); - file.delete(); - return entry; - - } - - private Path2D stringToPolygon(String polygonString, Model colorModel) { - String[] stringPointArray = polygonString.split(";"); - - List<Point2D> points = new ArrayList<>(); - for (String string : stringPointArray) { - if (!string.trim().equals("")) { - double x = Double.valueOf(string.split(",")[0]); - double y = Double.valueOf(string.split(",")[1]); - points.add(new Point2D.Double(x, y)); - } - } - - if (points.size() <= 2) { - points.clear(); - points.add(new Point2D.Double(0, 0)); - points.add(new Point2D.Double(colorModel.getWidth(), 0)); - points.add(new Point2D.Double(colorModel.getWidth(), colorModel.getHeight())); - points.add(new Point2D.Double(0, colorModel.getHeight())); - } - - Path2D polygon = new Path2D.Double(); - polygon.moveTo(points.get(0).getX(), points.get(0).getY()); - for (int i = 1; i < points.size(); i++) { - Point2D point = points.get(i); - polygon.lineTo(point.getX(), point.getY()); - } - polygon.closePath(); - return polygon; - } - - private List<Integer> deserializeIdList(String overlayIds) { - List<Integer> result = new ArrayList<>(); - String[] tmp = overlayIds.split(","); - for (String string : tmp) { - if (!string.equals("")) { - result.add(Integer.valueOf(string)); - } - } - return result; - } - - 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 { - 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"); - } - - Path2D polygon = stringToPolygon(polygonString, originalModel); - - // create model bounded by the polygon - SubModelCommand subModelCommand = new SubModelCommand(originalModel, polygon); - 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(","); - } - // Remove all colors - if (overlayIdsList.length > 0) { - - for (Element element : part.getElements()) { - element.setColor(Color.WHITE); - } - } - // Color with overlays - for (String overlayId : overlayIdsList) { - Layout overlay = layoutService.getLayoutById(Integer.parseInt(overlayId.trim()), token); - - ColorSchemaReader reader = new ColorSchemaReader(); - Collection<ColorSchema> schemas = reader.readColorSchema(overlay.getInputData().getFileContent()); - - new ColorModelCommand(part, schemas, getUserService().getColorExtractorForUser(user)).execute(); - } - - IConverter parser = getModelParser(handlerClass); - InputStream is = parser.exportModelToInputStream(part); - - String fileExtension = parser.getFileExtension(); - - UploadedFileEntry entry = new UploadedFileEntry(); - entry.setOriginalFileName("model." + fileExtension); - entry.setFileContent(IOUtils.toByteArray(is)); - entry.setLength(entry.getFileContent().length); - return entry; - - } - public Map<String, Object> getStatistics(String projectId, String token) throws SecurityException, ObjectNotFoundException { Map<String, Object> result = new TreeMap<>(); @@ -740,7 +483,8 @@ public class ProjectRestImpl extends BaseRestImpl { public Map<String, Object> removeProject(String token, String projectId, String path) throws SecurityException, QueryException { Project project = getProjectService().getProjectByProjectId(projectId, token); - if (getConfigurationService().getConfigurationValue(ConfigurationElementType.DEFAULT_MAP).equals(project.getProjectId())) { + if (getConfigurationService().getConfigurationValue(ConfigurationElementType.DEFAULT_MAP) + .equals(project.getProjectId())) { throw new OperationNotAllowedException("You cannot remove default map"); } getProjectService().removeProject(project, path, true, token); 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 aa9b1dbe903dcf34c32f13e835d5ec62cb9d3841..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 @@ -6,11 +6,13 @@ import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.CookieValue; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import com.fasterxml.jackson.core.JsonParseException; @@ -19,7 +21,13 @@ import com.fasterxml.jackson.databind.JsonMappingException; import lcsb.mapviewer.api.BaseController; import lcsb.mapviewer.api.ObjectNotFoundException; import lcsb.mapviewer.api.QueryException; +import lcsb.mapviewer.commands.CommandExecutionException; import lcsb.mapviewer.common.Configuration; +import lcsb.mapviewer.converter.ConverterException; +import lcsb.mapviewer.converter.graphics.DrawingException; +import lcsb.mapviewer.model.cache.FileEntry; +import lcsb.mapviewer.model.map.InconsistentModelException; +import lcsb.mapviewer.model.map.layout.InvalidColorSchemaException; import lcsb.mapviewer.services.SecurityException; @RestController @@ -63,4 +71,50 @@ public class ModelController extends BaseController { return modelController.updateModel(projectId, modelId, data, token); } + @RequestMapping(value = "/projects/{projectId}/models/{modelId}:downloadImage", method = { + RequestMethod.GET }, produces = { MediaType.APPLICATION_JSON_VALUE }) + public ResponseEntity<byte[]> getModelAsImage(// + @CookieValue(value = Configuration.AUTH_TOKEN) String token, // + @PathVariable(value = "projectId") String projectId, // + @PathVariable(value = "modelId") String modelId, // + @RequestParam(value = "handlerClass") String handlerClass, // + @RequestParam(value = "backgroundOverlayId", defaultValue = "") String backgroundOverlayId, // + @RequestParam(value = "overlayIds", defaultValue = "") String overlayIds, // + @RequestParam(value = "zoomLevel", defaultValue = "") String zoomLevel, // + @RequestParam(value = "polygonString", defaultValue = "") String polygonString// + ) throws SecurityException, QueryException, IOException, InvalidColorSchemaException, CommandExecutionException, + DrawingException { + + FileEntry file = modelController.getModelAsImage(token, projectId, modelId, handlerClass, backgroundOverlayId, + overlayIds, zoomLevel, polygonString); + MediaType type = MediaType.APPLICATION_OCTET_STREAM; + return ResponseEntity.ok().contentLength(file.getFileContent().length).contentType(type) + .header("Content-Disposition", "attachment; filename=" + file.getOriginalFileName()) + .body(file.getFileContent()); + } + + @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, // + @PathVariable(value = "modelId") String modelId, // + @RequestParam(value = "handlerClass") String handlerClass, // + @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 = "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, elementIds, reactionIds); + MediaType type = MediaType.APPLICATION_OCTET_STREAM; + return ResponseEntity.ok().contentLength(file.getFileContent().length).contentType(type) + .header("Content-Disposition", "attachment; filename=" + file.getOriginalFileName()) + .body(file.getFileContent()); + } + } \ No newline at end of file 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 5e3659dbc1a4d3ece5da1918825bc07267448108..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 @@ -1,29 +1,76 @@ package lcsb.mapviewer.api.projects.models; +import java.awt.Color; +import java.awt.geom.Path2D; +import java.awt.geom.PathIterator; +import java.awt.geom.Point2D; +import java.io.File; +import java.io.FileInputStream; +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; import java.util.Set; +import org.apache.commons.io.IOUtils; import org.apache.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import lcsb.mapviewer.api.BaseRestImpl; import lcsb.mapviewer.api.ObjectNotFoundException; import lcsb.mapviewer.api.QueryException; +import lcsb.mapviewer.commands.ClearColorModelCommand; +import lcsb.mapviewer.commands.ColorExtractor; +import lcsb.mapviewer.commands.ColorModelCommand; +import lcsb.mapviewer.commands.CommandExecutionException; +import lcsb.mapviewer.commands.CopyCommand; +import lcsb.mapviewer.commands.SetFixedHierarchyLevelCommand; +import lcsb.mapviewer.commands.SubModelCommand; import lcsb.mapviewer.common.Configuration; import lcsb.mapviewer.common.exception.InvalidArgumentException; +import lcsb.mapviewer.converter.ConverterException; +import lcsb.mapviewer.converter.IConverter; +import lcsb.mapviewer.converter.graphics.AbstractImageGenerator.Params; +import lcsb.mapviewer.converter.graphics.DrawingException; +import lcsb.mapviewer.converter.graphics.ImageGenerators; import lcsb.mapviewer.model.Project; +import lcsb.mapviewer.model.cache.FileEntry; +import lcsb.mapviewer.model.cache.UploadedFileEntry; +import lcsb.mapviewer.model.map.InconsistentModelException; +import lcsb.mapviewer.model.map.layout.ColorSchema; +import lcsb.mapviewer.model.map.layout.InvalidColorSchemaException; +import lcsb.mapviewer.model.map.layout.Layout; import lcsb.mapviewer.model.map.model.Model; import lcsb.mapviewer.model.map.model.ModelData; import lcsb.mapviewer.model.map.model.SubmodelType; +import lcsb.mapviewer.model.map.species.Element; import lcsb.mapviewer.model.user.PrivilegeType; +import lcsb.mapviewer.model.user.User; import lcsb.mapviewer.services.SecurityException; +import lcsb.mapviewer.services.interfaces.ILayoutService; +import lcsb.mapviewer.services.utils.ColorSchemaReader; +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 + * found <a href= + * "http://docs.oracle.com/javase/7/docs/api/java/awt/geom/PathIterator.html#currentSegment(double[])" + * >here</a> + */ + private static final int PATH_ITERATOR_SEGMENT_SIZE = 6; + + @Autowired + private ILayoutService layoutService; + /** * Default class logger. */ @@ -132,7 +179,6 @@ public class ModelRestImpl extends BaseRestImpl { } else { throw new InvalidArgumentException(); } - } private Double parseDouble(Object value) throws QueryException { @@ -156,4 +202,249 @@ public class ModelRestImpl extends BaseRestImpl { throw new QueryException("Don't know how to change " + value.getClass() + " into Double"); } } + + public FileEntry getModelAsModelFile(String token, String projectId, String modelId, String handlerClass, + 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 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, elementIdsList, reactionIdsList); + Model part = subModelCommand.execute(); + + // Get list of overlay ids + String[] overlayIdsList = stringListToArray(overlayIds); + // Remove all colors + if (overlayIdsList.length > 0) { + for (Element element : part.getElements()) { + element.setColor(Color.WHITE); + } + } + // Color with overlays + for (String overlayId : overlayIdsList) { + Layout overlay = layoutService.getLayoutById(Integer.parseInt(overlayId.trim()), token); + + ColorSchemaReader reader = new ColorSchemaReader(); + Collection<ColorSchema> schemas = reader.readColorSchema(overlay.getInputData().getFileContent()); + + new ColorModelCommand(part, schemas, getUserService().getColorExtractorForUser(user)).execute(); + } + + IConverter parser = getModelParser(handlerClass); + InputStream is = parser.exportModelToInputStream(part); + + String fileExtension = parser.getFileExtension(); + + UploadedFileEntry entry = new UploadedFileEntry(); + entry.setOriginalFileName("model." + fileExtension); + entry.setFileContent(IOUtils.toByteArray(is)); + entry.setLength(entry.getFileContent().length); + return entry; + + } + + 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, + QueryException, IOException, InvalidColorSchemaException, CommandExecutionException, DrawingException { + 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"); + } + + Layout overlay = null; + if (!backgroundOverlayId.equals("")) { + overlay = topModel.getLayoutByIdentifier(Integer.valueOf(backgroundOverlayId)); + + if (overlay == null) { + throw new ObjectNotFoundException("Unknown overlay in model. Layout.id=" + backgroundOverlayId); + } + } else { + if (topModel.getLayouts().size() > 0) { + overlay = topModel.getLayouts().get(0); + } + } + + Model colorModel = new CopyCommand(originalModel).execute(); + if (overlay != null) { + if (overlay.getInputData() != null) { + ColorSchemaReader reader = new ColorSchemaReader(); + Collection<ColorSchema> schemas = reader.readColorSchema(overlay.getInputData().getFileContent()); + + new ColorModelCommand(colorModel, schemas, getUserService().getColorExtractorForUser(user)).execute(); + } else if (overlay.getTitle().equals(BuildInLayout.CLEAN.getTitle())) { + // this might not return true if we change CLEAN.title in future... + + // if it's clean then remove coloring + new ClearColorModelCommand(colorModel).execute(); + } else if (overlay.isHierarchicalView()) { + new SetFixedHierarchyLevelCommand(colorModel, overlay.getHierarchyViewLevel()).execute(); + } + } + + Integer level = Configuration.MIN_ZOOM_LEVEL; + if (!zoomLevel.equals("")) { + level = Integer.valueOf(zoomLevel); + } + + Path2D polygon = stringToPolygon(polygonString, colorModel); + + Double minX = originalModel.getWidth(); + Double minY = originalModel.getHeight(); + Double maxX = 0.0; + Double maxY = 0.0; + + PathIterator pathIter = polygon.getPathIterator(null); + while (!pathIter.isDone()) { + final double[] segment = new double[PATH_ITERATOR_SEGMENT_SIZE]; + if (pathIter.currentSegment(segment) != PathIterator.SEG_CLOSE) { + minX = Math.min(minX, segment[0]); + maxX = Math.max(maxX, segment[0]); + minY = Math.min(minY, segment[1]); + maxY = Math.max(maxY, segment[1]); + } + pathIter.next(); + } + + maxX = Math.min(originalModel.getWidth(), maxX); + maxY = Math.min(originalModel.getHeight(), maxY); + minX = Math.max(0.0, minX); + minY = Math.max(0.0, minY); + + Double scale = Math.max(originalModel.getHeight(), originalModel.getWidth()) / (originalModel.getTileSize()); + + for (int i = level; i > Configuration.MIN_ZOOM_LEVEL; i--) { + scale /= 2; + } + + ColorExtractor colorExtractor = getUserService().getColorExtractorForUser(user); + + Params params = new Params().// + x(minX).// + y(minY).// + height((maxY - minY) / scale).// + width((maxX - minX) / scale).// + level(level - Configuration.MIN_ZOOM_LEVEL).// + nested(false).// automatically set nested view as invalid + scale(scale).// + colorExtractor(colorExtractor).// + sbgn(topModel.getProject().isSbgnFormat()).// + model(colorModel); + if (overlay != null) { + params.nested(overlay.isHierarchicalView()); + } + List<Integer> visibleLayoutIds = deserializeIdList(overlayIds); + for (Integer integer : visibleLayoutIds) { + Map<Object, ColorSchema> map = layoutService.getElementsForLayout(colorModel, integer, token); + params.addVisibleLayout(map); + } + + ImageGenerators imageGenerator = new ImageGenerators(); + String extension = imageGenerator.getExtension(handlerClass); + File file = File.createTempFile("map", "." + extension); + + imageGenerator.generate(handlerClass, params, file.getAbsolutePath()); + + UploadedFileEntry entry = new UploadedFileEntry(); + entry.setOriginalFileName("map." + extension); + entry.setFileContent(IOUtils.toByteArray(new FileInputStream(file))); + entry.setLength(entry.getFileContent().length); + file.delete(); + return entry; + + } + + private Path2D stringToPolygon(String polygonString, Model colorModel) { + String[] stringPointArray = polygonString.split(";"); + + List<Point2D> points = new ArrayList<>(); + for (String string : stringPointArray) { + if (!string.trim().equals("")) { + double x = Double.valueOf(string.split(",")[0]); + double y = Double.valueOf(string.split(",")[1]); + points.add(new Point2D.Double(x, y)); + } + } + + if (points.size() <= 2) { + points.clear(); + points.add(new Point2D.Double(0, 0)); + points.add(new Point2D.Double(colorModel.getWidth(), 0)); + points.add(new Point2D.Double(colorModel.getWidth(), colorModel.getHeight())); + points.add(new Point2D.Double(0, colorModel.getHeight())); + } + + Path2D polygon = new Path2D.Double(); + polygon.moveTo(points.get(0).getX(), points.get(0).getY()); + for (int i = 1; i < points.size(); i++) { + Point2D point = points.get(i); + polygon.lineTo(point.getX(), point.getY()); + } + polygon.closePath(); + return polygon; + } + + private List<Integer> deserializeIdList(String overlayIds) { + List<Integer> result = new ArrayList<>(); + String[] tmp = overlayIds.split(","); + for (String string : tmp) { + if (!string.equals("")) { + result.add(Integer.valueOf(string)); + } + } + return result; + } + } diff --git a/rest-api/src/test/java/lcsb/mapviewer/api/convert/ConvertRestImplTest.java b/rest-api/src/test/java/lcsb/mapviewer/api/convert/ConvertRestImplTest.java index 047dc151eb97251d2100ffab99867fed5b30afa5..195a8d73a56c803e0253ebcd57f1a73c9e012b71 100644 --- a/rest-api/src/test/java/lcsb/mapviewer/api/convert/ConvertRestImplTest.java +++ b/rest-api/src/test/java/lcsb/mapviewer/api/convert/ConvertRestImplTest.java @@ -187,9 +187,13 @@ public class ConvertRestImplTest extends RestTestFunctions { String result = convertRestImpl.convert(token, "CellDesigner_SBML", "SBML", content); ByteArrayOutputStream result1 = convertRestImpl.converToImage(token, "SBML", "svg", result); - FileOutputStream outputStream = new FileOutputStream("testFiles/convert/glycolysis2.svg"); + File output = new File("testFiles/convert/glycolysis2.svg"); + + FileOutputStream outputStream = new FileOutputStream(output); outputStream.write(result1.toByteArray()); outputStream.close(); + assertTrue(output.exists()); + output.delete(); } catch (Exception e) { diff --git a/rest-api/src/test/java/lcsb/mapviewer/api/projects/ProjectRestImplTest.java b/rest-api/src/test/java/lcsb/mapviewer/api/projects/ProjectRestImplTest.java index 79afcc01ea2719718cb3cd963afb71ac545c066d..60688c8ccacebe8141366abac7056c762baf23ea 100644 --- a/rest-api/src/test/java/lcsb/mapviewer/api/projects/ProjectRestImplTest.java +++ b/rest-api/src/test/java/lcsb/mapviewer/api/projects/ProjectRestImplTest.java @@ -4,9 +4,8 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.times; import java.util.ArrayList; @@ -28,17 +27,12 @@ import org.springframework.util.MultiValueMap; import com.google.gson.Gson; import lcsb.mapviewer.api.ObjectNotFoundException; -import lcsb.mapviewer.api.QueryException; import lcsb.mapviewer.api.RestTestFunctions; -import lcsb.mapviewer.common.exception.InvalidArgumentException; -import lcsb.mapviewer.converter.graphics.PdfImageGenerator; -import lcsb.mapviewer.converter.model.celldesigner.CellDesignerXmlParser; import lcsb.mapviewer.converter.zip.ImageZipEntryFile; import lcsb.mapviewer.converter.zip.LayoutZipEntryFile; import lcsb.mapviewer.converter.zip.ModelZipEntryFile; import lcsb.mapviewer.converter.zip.ZipEntryFile; import lcsb.mapviewer.model.Project; -import lcsb.mapviewer.model.cache.FileEntry; import lcsb.mapviewer.model.map.MiriamType; import lcsb.mapviewer.model.map.model.Model; import lcsb.mapviewer.persist.dao.ProjectDao; @@ -71,32 +65,6 @@ public class ProjectRestImplTest extends RestTestFunctions { public void tearDown() throws Exception { } - @Test - public void testGetModelAsImageForInvalidConverter() throws Exception { - try { - ProjectRestImpl projectRest = createMockProjectRest("testFiles/model/sample.xml"); - projectRest.getModelAsImage(token, "sample", "0", "", "", "", "", ""); - fail("Exception expected"); - } catch (InvalidArgumentException e) { - } catch (Exception e) { - e.printStackTrace(); - throw e; - } - } - - @Test - public void testGetModelAsImage() throws Exception { - try { - ProjectRestImpl projectRest = createMockProjectRest("testFiles/model/sample.xml"); - FileEntry result = projectRest.getModelAsImage(token, "sample", "0", PdfImageGenerator.class.getCanonicalName(), - "", "", "", ""); - assertNotNull(result); - } catch (Exception e) { - e.printStackTrace(); - throw e; - } - } - @Test public void testGetModelDataDependencies() throws Exception { try { @@ -117,55 +85,6 @@ public class ProjectRestImplTest extends RestTestFunctions { projectRest.getProject("unknown_model_id", token); } - @Test - public void testGetModelAsImage2() throws Exception { - try { - ProjectRestImpl projectRest = createMockProjectRest("testFiles/model/sample.xml"); - projectRest.getModelAsImage(token, "sample", "0", PdfImageGenerator.class.getCanonicalName(), "", "", "", ""); - } catch (Exception e) { - e.printStackTrace(); - throw e; - } - } - - @Test - public void testGetModelAsFileModel() throws Exception { - try { - ProjectRestImpl projectRest = createMockProjectRest("testFiles/model/sample.xml"); - projectRest.getModelAsModelFile(token, "sample", "0", "", "", "", "", ""); - fail("Exception expected"); - } catch (QueryException e) { - } catch (Exception e) { - e.printStackTrace(); - throw e; - } - } - - @Test - public void testGetModelAsFileModel2() throws Exception { - try { - ProjectRestImpl projectRest = createMockProjectRest("testFiles/model/sample.xml"); - projectRest.getModelAsModelFile(token, "sample", "0", CellDesignerXmlParser.class.getCanonicalName(), "", "", "", - "0,0;90,0;90,90;90,0"); - } catch (Exception e) { - e.printStackTrace(); - throw e; - } - } - - @Test - public void testGetModelAsFileModel3() throws Exception { - try { - ProjectRestImpl projectRest = createMockProjectRest("testFiles/model/sample.xml"); - projectRest.getModelAsModelFile(token, "sample", "0", "", "", "", "", "0,0;90,0;90,90;90,0"); - fail("Exception expected"); - } catch (QueryException e) { - } catch (Exception e) { - e.printStackTrace(); - throw e; - } - } - @Test public void testGetProject() throws Exception { try { 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 d3435cc35db0867789a427c34393ba3d98e1d809..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 @@ -1,12 +1,15 @@ package lcsb.mapviewer.api.projects.models; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.nullable; 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; @@ -14,8 +17,13 @@ import org.junit.Test; import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; +import lcsb.mapviewer.api.QueryException; import lcsb.mapviewer.api.RestTestFunctions; +import lcsb.mapviewer.common.exception.InvalidArgumentException; +import lcsb.mapviewer.converter.graphics.PdfImageGenerator; +import lcsb.mapviewer.converter.model.celldesigner.CellDesignerXmlParser; import lcsb.mapviewer.model.Project; +import lcsb.mapviewer.model.cache.FileEntry; import lcsb.mapviewer.model.map.model.Model; import lcsb.mapviewer.services.interfaces.IModelService; import lcsb.mapviewer.services.interfaces.IProjectService; @@ -93,4 +101,101 @@ public class ModelRestImplTest extends RestTestFunctions { return _modelRestImpl; } + @Test + public void testGetModelAsImageForInvalidConverter() throws Exception { + try { + ModelRestImpl modelRest = createMockProjectRest("testFiles/model/sample.xml"); + modelRest.getModelAsImage(token, "sample", "0", "", "", "", "", ""); + fail("Exception expected"); + } catch (InvalidArgumentException e) { + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + + @Test + public void testGetModelAsImage() throws Exception { + try { + ModelRestImpl modelRest = createMockProjectRest("testFiles/model/sample.xml"); + FileEntry result = modelRest.getModelAsImage(token, "sample", "0", PdfImageGenerator.class.getCanonicalName(), "", + "", "", ""); + assertNotNull(result); + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + + @Test + public void testGetModelAsImage2() throws Exception { + try { + ModelRestImpl modelRest = createMockProjectRest("testFiles/model/sample.xml"); + modelRest.getModelAsImage(token, "sample", "0", PdfImageGenerator.class.getCanonicalName(), "", "", "", ""); + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + + @Test + public void testGetModelAsFileModel() throws Exception { + try { + ModelRestImpl modelRest = createMockProjectRest("testFiles/model/sample.xml"); + modelRest.getModelAsModelFile(token, "sample", "0", "", "", "", "", "", null, null); + fail("Exception expected"); + } catch (QueryException e) { + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + + @Test + public void testGetModelAsFileModel2() throws Exception { + try { + ModelRestImpl modelRest = createMockProjectRest("testFiles/model/sample.xml"); + modelRest.getModelAsModelFile(token, "sample", "0", CellDesignerXmlParser.class.getCanonicalName(), "", "", "", + "0,0;90,0;90,90;90,0", null, null); + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + + @Test + 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", null, null); + fail("Exception expected"); + } catch (QueryException e) { + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + + @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; + } + } }