diff --git a/CHANGELOG b/CHANGELOG index cf80b16b0fec961e1a72a1f702e5faa7b181475b..7add9e01945b4afb6bd6cf94d3ff27b8aac1c711 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -11,6 +11,18 @@ minerva (12.1.0~alpha.0) experimental; urgency=medium -- Piotr Gawron <piotr.gawron@uni.lu> Wed, 25 Jul 2018 10:00:00 +0200 +minerva (12.0.2) stable; urgency=medium + * Bug fix: data overlay by annotation type fixed + * Bug fix: [plugin] getting reactions with set of id larger than 100 elements + works properly + * Bug fix: name of commented protein was remembered for the new comment + * Bug fix: setting zoom level wasn't ranged and validated + * Bug fix: when uploading data overlay there is a warning regarding mixed new + line characters when necessary + * Performance: tomcat inside docker image by default can use 3G of memory + + -- Piotr Gawron <piotr.gawron@uni.lu> Tue, 31 Jul 2018 13:00:00 +0200 + minerva (12.0.1) stable; urgency=medium * Bug fix: setting default zoom level on submap * Bug fix: opened submap had different background then current selection diff --git a/Docker/Dockerfile b/Docker/Dockerfile index 4cfae15c6f7834c910b4ff29f530c7431777cca8..d5910e1a2cd48a2e3f0371aea69ad88cdcfba783 100644 --- a/Docker/Dockerfile +++ b/Docker/Dockerfile @@ -45,6 +45,7 @@ ADD policy-rc.d /tmp/policy-rc.d RUN apt-get update +RUN sed -i "/JAVA_OPTS=\"-Djava.awt.headless=true -Xmx128m -XX:+UseConcMarkSweepGC\"/c\JAVA_OPTS=\"-Djava.awt.headless=true -Xmx3096m -XX:+UseConcMarkSweepGC\"" /etc/default/tomcat7 #when we install minerva allow to start services, so everything can be installed properly #but we need to disable tomcat7 because tomcat7 requires SYS_PTRACE and we cannot start it: diff --git a/annotation/src/main/java/lcsb/mapviewer/annotation/services/annotators/ChebiAnnotator.java b/annotation/src/main/java/lcsb/mapviewer/annotation/services/annotators/ChebiAnnotator.java index cc2af5f03a65e73a088b803350be2885206ba860..5a673aa4b636c7f0122d662bddb9f471ec6b534b 100644 --- a/annotation/src/main/java/lcsb/mapviewer/annotation/services/annotators/ChebiAnnotator.java +++ b/annotation/src/main/java/lcsb/mapviewer/annotation/services/annotators/ChebiAnnotator.java @@ -27,7 +27,6 @@ import lcsb.mapviewer.model.map.MiriamType; import lcsb.mapviewer.model.map.species.Chemical; import lcsb.mapviewer.modelutils.map.ElementUtils; import uk.ac.ebi.chebi.webapps.chebiWS.client.ChebiWebServiceClient; -import uk.ac.ebi.chebi.webapps.chebiWS.model.ChebiWebServiceFault_Exception; import uk.ac.ebi.chebi.webapps.chebiWS.model.DataItem; import uk.ac.ebi.chebi.webapps.chebiWS.model.Entity; import uk.ac.ebi.chebi.webapps.chebiWS.model.LiteEntity; @@ -205,7 +204,7 @@ public class ChebiAnnotator extends ElementAnnotator implements IExternalService } } } - } catch (ChebiWebServiceFault_Exception e) { + } catch (Exception e) { throw new ChebiSearchException("Problem with chebi connection", e); } return null; @@ -290,7 +289,7 @@ public class ChebiAnnotator extends ElementAnnotator implements IExternalService String value = miriamListToStringList(result); setCacheValue(query, value); - } catch (ChebiWebServiceFault_Exception e) { + } catch (Exception e) { throw new ChebiSearchException("Problem with chebi", e); } return result; @@ -300,7 +299,7 @@ public class ChebiAnnotator extends ElementAnnotator implements IExternalService * Serialize list of chebi identifiers. * * @param list - * list of chebi identfiers + * list of chebi identifiers * @return string with identifiers */ private String miriamListToStringList(List<MiriamData> list) { @@ -357,7 +356,6 @@ public class ChebiAnnotator extends ElementAnnotator implements IExternalService } try { ChebiWebServiceClient client = getClient(); - LiteEntityList entities = client.getLiteEntity(id, SearchCategory.CHEBI_ID, MAX_SEARCH_RESULTS_FROM_CHEBI_API, StarsCategory.ALL); List<LiteEntity> resultList = entities.getListElement(); @@ -374,7 +372,7 @@ public class ChebiAnnotator extends ElementAnnotator implements IExternalService setCacheValue("id: " + id, chebiSerializer.objectToString(result)); } return result; - } catch (ChebiWebServiceFault_Exception e) { + } catch (Exception e) { throw new ChebiSearchException("Problem with chebi", e); } } @@ -387,7 +385,7 @@ public class ChebiAnnotator extends ElementAnnotator implements IExternalService * identifier): "CHEBI:XXXXX" or "XXXXX" * @return common name of chemical * @throws ChebiSearchException - * thrown when there is a problemw ith accessing information from + * thrown when there is a problem with accessing information from * external chebi database */ protected String getChebiNameForChebiId(MiriamData id) throws ChebiSearchException { diff --git a/frontend-js/src/main/js/ServerConnector.js b/frontend-js/src/main/js/ServerConnector.js index b5f1f91ffc246eb2d9cf8487c0c153f3420c1afb..d7a7c127f013f4f2097aa51c5fc61504d3ad2916 100644 --- a/frontend-js/src/main/js/ServerConnector.js +++ b/frontend-js/src/main/js/ServerConnector.js @@ -74,6 +74,7 @@ ServerConnector.init = function () { self.removeListener("onDataLoadStop", listeners[i]); } + self.MAX_NUMBER_OF_IDS_IN_GET_QUERY = 100; }; ServerConnector.registerListenerType("onDataLoadStart"); ServerConnector.registerListenerType("onDataLoadStop"); @@ -238,10 +239,19 @@ ServerConnector._sendRequest = function (params) { * @returns {Promise} */ ServerConnector.sendPostRequest = function (url, params) { + var formParams = {}; + for (var key in params) { + if (params.hasOwnProperty(key)) { + formParams[key] = this.objectToRequestString(params[key]); + if (formParams[key] === undefined) { + formParams[key] = params[key]; + } + } + } return this.sendRequest({ method: "POST", url: url, - form: params + form: formParams }); }; @@ -289,6 +299,25 @@ ServerConnector.getServerBaseUrl = function () { return this._serverBaseUrl; }; +/** + * + * @param {Object} object + * @returns {string} + */ +ServerConnector.objectToRequestString = function (object) { + var value; + if (object instanceof Point) { + value = this.pointToString(object); + } else if (Object.prototype.toString.call(object) === '[object Array]') { + value = this.idsToString(object); + } else if (typeof object === 'string' || object instanceof String || !isNaN(object)) { + value = object.toString(); + } else { + value = undefined; + } + return value; +}; + ServerConnector.createGetParams = function (params, prefix) { var sorted = [], key; @@ -306,18 +335,12 @@ ServerConnector.createGetParams = function (params, prefix) { if (prefix !== undefined) { key = prefix + "." + key; } - if (value instanceof Point) { - value = this.pointToString(value); - } else if (Object.prototype.toString.call(value) === '[object Array]') { - value = this.idsToString(value); - } else if (typeof value === 'string' || value instanceof String || !isNaN(value)) { - } else { - result += this.createGetParams(value, key); - value = undefined; - } - if (value !== undefined && value !== "") { - result += key + "=" + value + "&"; + var serializedValue = this.objectToRequestString(value); + if (serializedValue === undefined) { + result += this.createGetParams(value, key); + } else if (serializedValue !== undefined && serializedValue !== "") { + result += key + "=" + serializedValue + "&"; } } return result; @@ -1513,6 +1536,15 @@ ServerConnector.getOverlayById = function (overlayId, projectId) { }); }; +/** + * + * @param {number} [params.modelId] + * @param {number[]} [params.ids] + * @param {number[]} [params.participantId] + * @param {string[]} [params.columns] + * @param {string} [params.projectId] + * @returns {*} + */ ServerConnector.getReactions = function (params) { var self = this; var queryParams = { @@ -1531,7 +1563,7 @@ ServerConnector.getReactions = function (params) { }; return self.getProjectId(params.projectId).then(function (result) { queryParams.projectId = result; - if (filterParams.id.length > 100 || filterParams.participantId.length > 100) { + if (filterParams.id.length > self.MAX_NUMBER_OF_IDS_IN_GET_QUERY || filterParams.participantId.length > self.MAX_NUMBER_OF_IDS_IN_GET_QUERY) { return self.sendPostRequest(self.getReactionsUrl(queryParams), filterParams); } else { return self.sendGetRequest(self.getReactionsUrl(queryParams, filterParams)); @@ -1571,7 +1603,7 @@ ServerConnector.getAliases = function (params) { }; return self.getProjectId(params.projectId).then(function (result) { queryParams.projectId = result; - if (filterParams.id.length > 100) { + if (filterParams.id.length > self.MAX_NUMBER_OF_IDS_IN_GET_QUERY) { return self.sendPostRequest(self.getAliasesUrl(queryParams), filterParams); } else { return self.sendGetRequest(self.getAliasesUrl(queryParams, filterParams)); diff --git a/frontend-js/src/main/js/gui/AddOverlayDialog.js b/frontend-js/src/main/js/gui/AddOverlayDialog.js index 497045042e7987b2dfe9674b8806d69ad4897ec8..c1ebf8a420f517009c356d065a73b9d95f8ae0fa 100644 --- a/frontend-js/src/main/js/gui/AddOverlayDialog.js +++ b/frontend-js/src/main/js/gui/AddOverlayDialog.js @@ -154,6 +154,10 @@ AddOverlayDialog.prototype.processFile = function (file) { if (overlay.getType() !== undefined) { typeSelect.val(overlay.getType()); } + if (overlayParser.containsMixedNewLineCharacters(evt.target.result)) { + GuiConnector.warn("Selected file contains new line characters from different operating systems " + + "(MAC/Windows/Linux). This might cause confusion when reading the file in the editor later on.") + } resolve(self.getFileContent()); } catch (error) { reject(error); diff --git a/frontend-js/src/main/js/gui/CommentDialog.js b/frontend-js/src/main/js/gui/CommentDialog.js index 4cfd4d4cd8b5f561cff3597d26997d3f7b32a57c..0ca87663084dad9a3f1217e80ac3c515b973a3dc 100644 --- a/frontend-js/src/main/js/gui/CommentDialog.js +++ b/frontend-js/src/main/js/gui/CommentDialog.js @@ -38,13 +38,13 @@ function createRow(elements) { return row; } -CommentDialog.prototype.open = function (types) { +CommentDialog.prototype.open = function (identifiedElements) { var self = this; self.setTypes([CommentDialog.GENERAL]); var promises = [CommentDialog.GENERAL]; - for (var i = 0; i < types.length; i++) { - var ie = types[i]; + for (var i = 0; i < identifiedElements.length; i++) { + var ie = identifiedElements[i]; if (ie.getType() === "ALIAS") { promises.push(self.getMap().getSubmapById(ie.getModelId()).getModel().getAliasById(ie.getId(), true)); } else if (ie.getType() === "REACTION") { @@ -182,6 +182,7 @@ CommentDialog.prototype.setTypes = function (types) { typeOptions.value = 0; this._types = types; + typeOptions.onchange(); }; CommentDialog.prototype.getTypes = function () { diff --git a/frontend-js/src/main/js/gui/admin/EditProjectDialog.js b/frontend-js/src/main/js/gui/admin/EditProjectDialog.js index 4e1127816fd5763d179ea7f7d3d66bce21ae5b04..76286f728493369b9a42a301d4251a2d959e3595 100644 --- a/frontend-js/src/main/js/gui/admin/EditProjectDialog.js +++ b/frontend-js/src/main/js/gui/admin/EditProjectDialog.js @@ -114,7 +114,7 @@ EditProjectDialog.prototype.addTab = function (params) { navigationObject: navLi, navigationBar: params.tabMenuDiv }); - $(contentDiv).css("overflow","auto"); + $(contentDiv).css("overflow", "auto"); if (params.content !== undefined) { contentDiv.appendChild(params.content); @@ -821,7 +821,12 @@ function getValueOrEmpty(value) { } } -EditProjectDialog.prototype.mapToTableRow = function (map, users) { +/** + * + * @param {MapModel} map + * @returns {Array} + */ +EditProjectDialog.prototype.mapToTableRow = function (map) { var row = []; var id = map.getId(); var centerX = getValueOrEmpty(map.getDefaultCenterX()); @@ -831,7 +836,17 @@ EditProjectDialog.prototype.mapToTableRow = function (map, users) { row[1] = map.getName(); row[2] = "<input name='defaultCenterX-" + id + "' value='" + centerX + "'/>"; row[3] = "<input name='defaultCenterY-" + id + "' value='" + centerY + "'/>"; - row[4] = "<input name='defaultZoomLevel-" + id + "' value='" + zoomLevel + "'/>"; + var zoomLevelSelect = "<select name='defaultZoomLevel-" + id + "' value='" + zoomLevel + "'>" + + "<option value=''>---</option>"; + for (var i = map.getMinZoom(); i <= map.getMaxZoom(); i++) { + var selected = ""; + if (i === zoomLevel) { + selected = " selected "; + } + zoomLevelSelect += "<option value='" + i + "' " + selected + ">" + (i - map.getMinZoom()) + "</option>"; + } + zoomLevelSelect += "</select>"; + row[4] = zoomLevelSelect; row[5] = "<button name='saveMap' data='" + id + "'><i class=\"fa fa-save\" style=\"font-size:17px\"></i></button>"; return row; @@ -921,8 +936,10 @@ EditProjectDialog.prototype.saveOverlay = function (overlayId) { EditProjectDialog.prototype.saveMap = function (mapId) { var self = this; var map = self._mapsById[mapId]; - map.setDefaultCenterX($("[name='defaultCenterX-" + mapId + "']", self.getElement())[0].value); - map.setDefaultCenterY($("[name='defaultCenterY-" + mapId + "']", self.getElement())[0].value); + var centerX = parseInt($("[name='defaultCenterX-" + mapId + "']", self.getElement())[0].value); + var centerY = parseInt($("[name='defaultCenterY-" + mapId + "']", self.getElement())[0].value); + map.setDefaultCenterX(centerX); + map.setDefaultCenterY(centerY); map.setDefaultZoomLevel($("[name='defaultZoomLevel-" + mapId + "']", self.getElement())[0].value); return ServerConnector.updateModel({projectId: self.getProject().getProjectId(), model: map}); diff --git a/frontend-js/src/main/js/map/OverlayParser.js b/frontend-js/src/main/js/map/OverlayParser.js index 320c0b936c4e09eedceea040c4c5f88e58eb7541..239de8d595203d790a3d6ec10662ce9c0c8c1dfe 100644 --- a/frontend-js/src/main/js/map/OverlayParser.js +++ b/frontend-js/src/main/js/map/OverlayParser.js @@ -9,13 +9,24 @@ function OverlayParser() { /** * - * @param {string| Uint8Array|ArrayBuffer} content - * @returns {DataOverlay} + * @param {string| Uint8Array | ArrayBuffer} content + * @returns {string} + * @private */ -OverlayParser.prototype.parse = function (content) { +OverlayParser.prototype._extractContent = function (content) { if (content instanceof Uint8Array || content instanceof ArrayBuffer) { content = new TextDecoder("UTF8").decode(content); } + return content; +}; + +/** + * + * @param {string| Uint8Array|ArrayBuffer} content + * @returns {DataOverlay} + */ +OverlayParser.prototype.parse = function (content) { + content = this._extractContent(content); var data = {content: content}; var lines = content.split("\n"); for (var i = 0; i < lines.length; i++) { @@ -42,5 +53,36 @@ OverlayParser.prototype.parse = function (content) { return new DataOverlay(data); }; +/** + * + * @param {string| Uint8Array | ArrayBuffer} content + * @returns {boolean} + */ +OverlayParser.prototype.containsMixedNewLineCharacters = function (content) { + content = this._extractContent(content); + var newLineRegEx = /[\r\n]+/g; + var match = newLineRegEx.exec(content); + var newLineFormats = {}; + var counter = 0; + while (match !== null && match !== undefined) { + var foundMultiplication = false; + var key = ''; + //this is just a heuristic - let's assume there are at most 10 empty lines in a file + for (var i = 0; i < 10; i++) { + key += match[0]; + if (newLineFormats[key]) { + foundMultiplication = true; + } else { + newLineFormats[key] = true; + } + } + if (!foundMultiplication) { + counter++; + } + match = newLineRegEx.exec(content); + } + return counter > 1; +}; + module.exports = OverlayParser; diff --git a/frontend-js/src/main/js/map/data/MapModel.js b/frontend-js/src/main/js/map/data/MapModel.js index 2173114711ad26566674abb7edb539d4d5d8f0c3..bbe8d3236763325946f391fa3fdeb4c38782667f 100644 --- a/frontend-js/src/main/js/map/data/MapModel.js +++ b/frontend-js/src/main/js/map/data/MapModel.js @@ -455,8 +455,16 @@ MapModel.prototype.getDefaultZoomLevel = function () { return this._defaultZoomLevel; }; +/** + * + * @param {number} defaultZoomLevel + */ MapModel.prototype.setDefaultZoomLevel = function (defaultZoomLevel) { - this._defaultZoomLevel = defaultZoomLevel; + if (!isNaN(defaultZoomLevel)) { + this._defaultZoomLevel = defaultZoomLevel; + } else { + this._defaultZoomLevel = null; + } }; /** @@ -467,8 +475,16 @@ MapModel.prototype.getDefaultCenterX = function () { return this._defaultCenterX; }; +/** + * + * @param {number} defaultCenterX + */ MapModel.prototype.setDefaultCenterX = function (defaultCenterX) { - this._defaultCenterX = defaultCenterX; + if (!isNaN(defaultCenterX)) { + this._defaultCenterX = defaultCenterX; + } else { + this._defaultCenterX = null; + } }; /** @@ -480,7 +496,11 @@ MapModel.prototype.getDefaultCenterY = function () { }; MapModel.prototype.setDefaultCenterY = function (defaultCenterY) { - this._defaultCenterY = defaultCenterY; + if (!isNaN(defaultCenterY)) { + this._defaultCenterY = defaultCenterY; + } else { + this._defaultCenterY = null; + } }; MapModel.prototype.getSubmodelType = function () { diff --git a/frontend-js/src/test/js/ServerConnector-test.js b/frontend-js/src/test/js/ServerConnector-test.js index b157e2232c241cbf76113e2aeaea049cc8764767..d7fab5dc49f8276bdea510ec565740b569b53484 100644 --- a/frontend-js/src/test/js/ServerConnector-test.js +++ b/frontend-js/src/test/js/ServerConnector-test.js @@ -13,6 +13,7 @@ var LayoutAlias = require('../../main/js/map/data/LayoutAlias'); var MapModel = require('../../main/js/map/data/MapModel'); var NetworkError = require('../../main/js/NetworkError'); var Project = require('../../main/js/map/data/Project'); +var Point = require('../../main/js/map/canvas/Point'); var Reaction = require('../../main/js/map/data/Reaction'); var ServerConnector = require('../../main/js/ServerConnector'); var SecurityError = require('../../main/js/SecurityError'); @@ -110,7 +111,7 @@ describe('ServerConnector', function () { }); }); it('without ids', function () { - return ServerConnector.getReactions([]).then(function (result) { + return ServerConnector.getReactions({}).then(function (result) { assert.equal(result.length, 28); var reaction = result[0]; assert.ok(reaction instanceof Reaction); @@ -118,6 +119,32 @@ describe('ServerConnector', function () { assert.equal(reaction.getModelId(), 15781); }); }); + + it('with ids', function () { + return ServerConnector.getReactions({ + modelId: 15781, + participantId: [329156, 329157, 329158, 329159, 329160, 329161, 329162, 329163, 329164, 329165, 329166, 329167, 329168, 329169, 329170, 329171, 329172, 329173, 329174, 329175, 329176, 329177, 329178, 329179, 329180, 329181, 329182, 329183, 329184, 329185] + }).then(function (result) { + assert.equal(result.length, 28); + var reaction = result[0]; + assert.ok(reaction instanceof Reaction); + assert.equal(reaction.getId(), 153524); + assert.equal(reaction.getModelId(), 15781); + }); + }); + it('with ids when asking for too many elements for gett query', function () { + ServerConnector.MAX_NUMBER_OF_IDS_IN_GET_QUERY = 0; + return ServerConnector.getReactions({ + modelId: 15781, + participantId: [329167] + }).then(function (result) { + assert.equal(result.length, 5); + var reaction = result[0]; + assert.ok(reaction instanceof Reaction); + assert.equal(reaction.getId(), 153518); + assert.equal(reaction.getModelId(), 15781); + }); + }); }); @@ -420,4 +447,23 @@ describe('ServerConnector', function () { }); + describe('objectToRequestString', function () { + it('string', function () { + assert.equal("test_string", ServerConnector.objectToRequestString("test_string")); + }); + it('number', function () { + assert.equal("12", ServerConnector.objectToRequestString(12)); + }); + it('point', function () { + assert.equal("0.00,10.00", ServerConnector.objectToRequestString(new Point(0, 10))); + }); + it('array of ids', function () { + assert.equal("1,4", ServerConnector.objectToRequestString([1, 4])); + }); + it('not sorted array of ids', function () { + assert.equal("1,4,5", ServerConnector.objectToRequestString([5, 1, 4])); + }); + }); + + }); diff --git a/frontend-js/src/test/js/map/OverlayParser-test.js b/frontend-js/src/test/js/map/OverlayParser-test.js index 48ce28d457854d75db0760b5b895aefa11f9ee66..a79ced51117e2e786a780e87053bddfdceac1859 100644 --- a/frontend-js/src/test/js/map/OverlayParser-test.js +++ b/frontend-js/src/test/js/map/OverlayParser-test.js @@ -42,5 +42,50 @@ describe('OverlayParser', function () { }); }); }); + describe('containsMixedNewLineCharacters', function () { + it('normal file', function () { + return ServerConnector.sendGetRequest("testFiles/overlay/good.txt").then(function (fileContent) { + var parser = new OverlayParser(); + assert.notOk(parser.containsMixedNewLineCharacters(fileContent)); + }); + }); + it('windows/linux mix', function () { + var content = "line1\n\rline2\n"; + var parser = new OverlayParser(); + assert.ok(parser.containsMixedNewLineCharacters(content)); + }); + + it('windows empty lines', function () { + var content = "line1\n\rline2\n\r\n\rline4"; + var parser = new OverlayParser(); + assert.notOk(parser.containsMixedNewLineCharacters(content)); + }); + + it('windows/mac mix', function () { + var content = "line1\n\rline2\r"; + var parser = new OverlayParser(); + assert.ok(parser.containsMixedNewLineCharacters(content)); + }); + + it('mac empty lines', function () { + var content = "line1\rline2\r\rline4"; + var parser = new OverlayParser(); + assert.notOk(parser.containsMixedNewLineCharacters(content)); + }); + + it('windows/mac mix 2', function () { + var content = "line1\n\r\rline2\n\rline3"; + var parser = new OverlayParser(); + assert.ok(parser.containsMixedNewLineCharacters(content)); + }); + + it('linux empty lines', function () { + var content = "line1\nline2\n\nline4"; + var parser = new OverlayParser(); + assert.notOk(parser.containsMixedNewLineCharacters(content)); + }); + + + }); }); diff --git a/frontend-js/testFiles/apiCalls/projects/sample/models/15781/bioEntities/reactions/POST_participantId=329167&token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/projects/sample/models/15781/bioEntities/reactions/POST_participantId=329167&token=MOCK_TOKEN_ID& new file mode 100644 index 0000000000000000000000000000000000000000..dcf64c8357fb8c21d2c6ba4eeed2cddf02eeb5c2 --- /dev/null +++ b/frontend-js/testFiles/apiCalls/projects/sample/models/15781/bioEntities/reactions/POST_participantId=329167&token=MOCK_TOKEN_ID& @@ -0,0 +1 @@ +[{"centerPoint":{"x":142.99978766600722,"y":179.00261878591084},"hierarchyVisibilityLevel":null,"id":153518,"kineticLaw":null,"lines":[{"start":{"x":141.01308884552796,"y":203.5052375718217},"end":{"x":142.676524190943,"y":182.98953497836953},"type":"START"},{"start":{"x":143.32305114107143,"y":175.01570259345215},"end":{"x":144.98648648648648,"y":154.5},"type":"END"}],"modelId":15781,"modifiers":[],"notes":"","products":[{"aliasId":329167,"stoichiometry":null}],"reactants":[{"aliasId":329169,"stoichiometry":null}],"reactionId":"re8","references":[],"type":"State transition"},{"centerPoint":{"x":92.15973884958811,"y":136.13620918163832},"hierarchyVisibilityLevel":null,"id":153512,"kineticLaw":null,"lines":[{"start":{"x":75.73715058611361,"y":134.3476104598738},"end":{"x":88.18325303297577,"y":135.7031265679479},"type":"START"},{"start":{"x":96.13622466620043,"y":136.56929179532878},"end":{"x":108.58232711306259,"y":137.92480790340286},"type":"END"}],"modelId":15781,"modifiers":[],"notes":"","products":[{"aliasId":329167,"stoichiometry":null}],"reactants":[{"aliasId":329168,"stoichiometry":null}],"reactionId":"re4","references":[],"type":"State transition"},{"centerPoint":{"x":128.5,"y":47.0},"hierarchyVisibilityLevel":null,"id":153510,"kineticLaw":null,"lines":[{"start":{"x":92.0,"y":36.98039215686274},"end":{"x":124.64269540833152,"y":45.94113207287532},"type":"START"},{"start":{"x":132.35730459166848,"y":48.05886792712468},"end":{"x":165.0,"y":57.01960784313726},"type":"END"},{"start":{"x":144.03021943732247,"y":129.5},"end":{"x":131.99804583067973,"y":53.145215648491444},"type":"MIDDLE"}],"modelId":15781,"modifiers":[{"aliasId":329167,"stoichiometry":null}],"notes":"","products":[{"aliasId":329179,"stoichiometry":null}],"reactants":[{"aliasId":329173,"stoichiometry":null}],"reactionId":"re5","references":[],"type":"State transition"},{"centerPoint":{"x":172.17324895317853,"y":109.17253521126761},"hierarchyVisibilityLevel":null,"id":153504,"kineticLaw":null,"lines":[{"start":{"x":155.9662162162162,"y":129.5},"end":{"x":169.67962640764847,"y":112.300129590407},"type":"START"},{"start":{"x":174.6668714987086,"y":106.04494083212823},"end":{"x":188.38028169014086,"y":88.84507042253522},"type":"END"}],"modelId":15781,"modifiers":[],"notes":"","products":[{"aliasId":329179,"stoichiometry":null}],"reactants":[{"aliasId":329167,"stoichiometry":null}],"reactionId":"re3","references":[],"type":"State transition"},{"centerPoint":{"x":196.68292177751908,"y":142.47367216614504},"hierarchyVisibilityLevel":null,"id":153499,"kineticLaw":null,"lines":[{"start":{"x":180.0362865221489,"y":142.31809613572102},"end":{"x":192.68309645382215,"y":142.43629062106376},"type":"START"},{"start":{"x":200.68274710121602,"y":142.5110537112263},"end":{"x":213.32955703288923,"y":142.62924819656908},"type":"END"}],"modelId":15781,"modifiers":[],"notes":"","products":[{"aliasId":329172,"stoichiometry":null}],"reactants":[{"aliasId":329167,"stoichiometry":null}],"reactionId":"re10","references":[],"type":"State transition"}] \ No newline at end of file diff --git a/model-command/src/main/java/lcsb/mapviewer/commands/ColorModelCommand.java b/model-command/src/main/java/lcsb/mapviewer/commands/ColorModelCommand.java index dc51d7bd73453defe5766ff822ca1c53d2f436fa..0604eb7b481275c4ed3a5633bcbbfa0ec6712451 100644 --- a/model-command/src/main/java/lcsb/mapviewer/commands/ColorModelCommand.java +++ b/model-command/src/main/java/lcsb/mapviewer/commands/ColorModelCommand.java @@ -221,7 +221,14 @@ public class ColorModelCommand extends ModelCommand { } } for (MiriamData md : schema.getMiriamData()) { - if (!element.getMiriamData().contains(md)) { + boolean found = false; + for (MiriamData elementMiriamData : element.getMiriamData()) { + if (elementMiriamData.getDataType().equals(md.getDataType()) + && elementMiriamData.getResource().equals(md.getResource())) { + found = true; + } + } + if (!found) { return false; } } diff --git a/model-command/src/test/java/lcsb/mapviewer/commands/ColorModelCommandTest.java b/model-command/src/test/java/lcsb/mapviewer/commands/ColorModelCommandTest.java index 7d0d731afd3c9ca331c41b0b6391db033ca863e3..a7e8702c8fa6596d13dec3033575fef71122e445 100644 --- a/model-command/src/test/java/lcsb/mapviewer/commands/ColorModelCommandTest.java +++ b/model-command/src/test/java/lcsb/mapviewer/commands/ColorModelCommandTest.java @@ -360,6 +360,61 @@ public class ColorModelCommandTest extends CommandTestFunctions { } + @Test + public void testSpeciesMatchWithMiriamData() throws Exception { + try { + GenericColorSchema colorSchema = new GenericColorSchema(); + colorSchema.setName("s1"); + colorSchema.addMiriamData(new MiriamData(MiriamType.HGNC_SYMBOL, "SNCA")); + + GenericColorSchema colorSchema2 = new GenericColorSchema(); + colorSchema2.setName("s1"); + colorSchema2.addMiriamData(new MiriamData(MiriamType.HGNC_SYMBOL, "PARK7")); + + GenericProtein species = new GenericProtein("id"); + species.setName("s1"); + species.addMiriamData(new MiriamData(MiriamType.HGNC_SYMBOL, "SNCA")); + + List<ColorSchema> schemas = new ArrayList<>(); + schemas.add(colorSchema); + + ColorModelCommand factory = new ColorModelCommand(new ModelFullIndexed(null), schemas, colorExtractor); + + assertTrue(factory.match(species, colorSchema)); + assertFalse(factory.match(species, colorSchema2)); + + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + + } + + @Test + public void testSpeciesMatchWithMiriamDataDifferentAnnotator() throws Exception { + try { + GenericColorSchema colorSchema = new GenericColorSchema(); + colorSchema.setName("s1"); + colorSchema.addMiriamData(new MiriamData(MiriamType.HGNC_SYMBOL, "SNCA")); + + GenericProtein species = new GenericProtein("id"); + species.setName("s1"); + species.addMiriamData(new MiriamData(MiriamType.HGNC_SYMBOL, "SNCA", Object.class)); + + List<ColorSchema> schemas = new ArrayList<>(); + schemas.add(colorSchema); + + ColorModelCommand factory = new ColorModelCommand(new ModelFullIndexed(null), schemas, colorExtractor); + + assertTrue(factory.match(species, colorSchema)); + + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + + } + @Test public void testReactionMatchWithProteinMiriamData() throws Exception { try { diff --git a/persist/src/db/12.0.2/fix_db_20180731.sql b/persist/src/db/12.0.2/fix_db_20180731.sql new file mode 100644 index 0000000000000000000000000000000000000000..d4a1bab394e65235f4c3005ed11554aa303fafac --- /dev/null +++ b/persist/src/db/12.0.2/fix_db_20180731.sql @@ -0,0 +1,2 @@ +-- issue #461 - duplicates in reaction ids resolved +update reaction_table r set idreaction=concat(r.idreaction,'_',r.iddb) from (select idreaction, model_iddb from reaction_table group by idreaction, model_iddb having count(*)>1) t where r.idreaction=t.idreaction and r.model_iddb=t.model_iddb; 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 78c6e8a518283853d4616af260f59264de0ff694..5e3659dbc1a4d3ece5da1918825bc07267448108 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 @@ -138,6 +138,8 @@ public class ModelRestImpl extends BaseRestImpl { private Double parseDouble(Object value) throws QueryException { if (value instanceof Double) { return (Double) value; + } else if (value instanceof Integer) { + return ((Integer) value).doubleValue(); } else if (value instanceof String) { if (((String) value).equalsIgnoreCase("")) { return null; @@ -151,7 +153,7 @@ public class ModelRestImpl extends BaseRestImpl { } else if (value == null) { return null; } else { - throw new InvalidArgumentException(); + throw new QueryException("Don't know how to change " + value.getClass() + " into Double"); } } }