diff --git a/CHANGELOG b/CHANGELOG index 852874c6df11e3764d8885047c1849089f040410..9e131afa95861b8d35620c527af4bc3becf624db 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,8 @@ +minerva (13.1.4) stable; urgency=medium + * Bug fix:search by drugs didn't check synonyms in chembl database + + -- Piotr Gawron <piotr.gawron@uni.lu> Wed, 21 Aug 2019 17:00:00 +0200 + minerva (13.1.3) stable; urgency=medium * Bug fix: refreshing list of projects or list of users doesn't change active page (#870) diff --git a/annotation/src/main/java/lcsb/mapviewer/annotation/services/ChEMBLParser.java b/annotation/src/main/java/lcsb/mapviewer/annotation/services/ChEMBLParser.java index 3a7519a5f3488d30759204fd1921b528424e0625..3d85947424392f8c46f4c03955785188a71e77a8 100644 --- a/annotation/src/main/java/lcsb/mapviewer/annotation/services/ChEMBLParser.java +++ b/annotation/src/main/java/lcsb/mapviewer/annotation/services/ChEMBLParser.java @@ -64,6 +64,11 @@ public class ChEMBLParser extends DrugAnnotation implements IExternalService { */ private static final String DRUG_NAME_API_URL = "https://www.ebi.ac.uk/chembl/api/data/molecule?pref_name__exact="; + /** + * Url that access data of drug identified by name. + */ + private static final String DRUG_SYNONYM_API_URL = "https://www.ebi.ac.uk/chembl/api/data/molecule?molecule_synonyms__molecule_synonym__iexact="; + /** * Url that access target by identifier. */ @@ -366,29 +371,22 @@ public class ChEMBLParser extends DrugAnnotation implements IExternalService { String page = getWebPageContent(accessUrl); Document document = XmlParser.getXmlDocumentFromString(page); - Node response = XmlParser.getNode("response", document.getChildNodes()); - Node molecules = XmlParser.getNode("molecules", response.getChildNodes()); - - NodeList list = molecules.getChildNodes(); - - for (int i = 0; i < list.getLength(); i++) { - Node node = list.item(i); - if (node.getNodeType() == Node.ELEMENT_NODE) { - if (node.getNodeName().equalsIgnoreCase("molecule")) { - if (drug == null) { - drug = parseDrug(node); - } else { - logger.warn("More drugs than one found for query: " + query); - } - } - } + List<Drug> drugs = extractDrugsFromDocument(document); + if (drugs.size()==0) { + accessUrl = DRUG_SYNONYM_API_URL + name; + page = getWebPageContent(accessUrl); + document = XmlParser.getXmlDocumentFromString(page); + drugs = extractDrugsFromDocument(document); + } + if (drugs.size()>1) { + logger.warn("More drugs than one found for query: " + query); } - if (drug == null) { + if (drugs.size() == 0) { return null; } - setCacheValue(query, getDrugSerializer().objectToString(drug)); - return drug; + setCacheValue(query, getDrugSerializer().objectToString(drugs.get(0))); + return drugs.get(0); } catch (IOException e) { throw new DrugSearchException("Problem with accessing CHEMBL database", e); } catch (InvalidXmlSchemaException e) { @@ -396,6 +394,24 @@ public class ChEMBLParser extends DrugAnnotation implements IExternalService { } } + private List<Drug> extractDrugsFromDocument(Document document) throws DrugSearchException { + List<Drug> result = new ArrayList<>(); + Node response = XmlParser.getNode("response", document.getChildNodes()); + Node molecules = XmlParser.getNode("molecules", response.getChildNodes()); + + NodeList list = molecules.getChildNodes(); + + for (int i = 0; i < list.getLength(); i++) { + Node node = list.item(i); + if (node.getNodeType() == Node.ELEMENT_NODE) { + if (node.getNodeName().equalsIgnoreCase("molecule")) { + result.add(parseDrug(node)); + } + } + } + return result; + } + /** * Parse xml node repesenting drug and returns drug with information obtained * from there and other places in chembl API. diff --git a/annotation/src/test/java/lcsb/mapviewer/annotation/services/ChEMBLParserTest.java b/annotation/src/test/java/lcsb/mapviewer/annotation/services/ChEMBLParserTest.java index 8fa920f651688e85b50daf5a607e0493b1b367f7..81975207903a0b61a29086e0714ba1114ca33c3a 100644 --- a/annotation/src/test/java/lcsb/mapviewer/annotation/services/ChEMBLParserTest.java +++ b/annotation/src/test/java/lcsb/mapviewer/annotation/services/ChEMBLParserTest.java @@ -1,20 +1,11 @@ package lcsb.mapviewer.annotation.services; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.nullable; +import static org.junit.Assert.*; +import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.when; import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; +import java.util.*; import org.apache.log4j.Logger; import org.junit.Test; @@ -23,22 +14,11 @@ import org.springframework.beans.factory.annotation.Autowired; import org.w3c.dom.Node; import lcsb.mapviewer.annotation.AnnotationTestFunctions; -import lcsb.mapviewer.annotation.cache.GeneralCacheInterface; -import lcsb.mapviewer.annotation.cache.PermanentDatabaseLevelCacheInterface; -import lcsb.mapviewer.annotation.cache.SourceNotAvailable; -import lcsb.mapviewer.annotation.cache.WebPageDownloader; -import lcsb.mapviewer.annotation.cache.XmlSerializer; -import lcsb.mapviewer.annotation.data.Drug; -import lcsb.mapviewer.annotation.data.Target; -import lcsb.mapviewer.annotation.data.TargetType; -import lcsb.mapviewer.annotation.services.annotators.AnnotatorException; -import lcsb.mapviewer.annotation.services.annotators.HgncAnnotator; -import lcsb.mapviewer.annotation.services.annotators.UniprotAnnotator; -import lcsb.mapviewer.annotation.services.annotators.UniprotSearchException; +import lcsb.mapviewer.annotation.cache.*; +import lcsb.mapviewer.annotation.data.*; +import lcsb.mapviewer.annotation.services.annotators.*; import lcsb.mapviewer.common.exception.InvalidArgumentException; -import lcsb.mapviewer.model.map.MiriamData; -import lcsb.mapviewer.model.map.MiriamRelationType; -import lcsb.mapviewer.model.map.MiriamType; +import lcsb.mapviewer.model.map.*; public class ChEMBLParserTest extends AnnotationTestFunctions { Logger logger = Logger.getLogger(ChEMBLParserTest.class); @@ -349,7 +329,8 @@ public class ChEMBLParserTest extends AnnotationTestFunctions { try { chemblParser.setCache(null); WebPageDownloader mockDownloader = Mockito.mock(WebPageDownloader.class); - when(mockDownloader.getFromNetwork(anyString(), anyString(), nullable(String.class))).thenThrow(new IOException()); + when(mockDownloader.getFromNetwork(anyString(), anyString(), nullable(String.class))) + .thenThrow(new IOException()); chemblParser.setWebPageDownloader(mockDownloader); chemblParser.getTargetFromId(new MiriamData(MiriamType.CHEMBL_TARGET, "water")); fail("Exception expected"); @@ -411,7 +392,8 @@ public class ChEMBLParserTest extends AnnotationTestFunctions { try { chemblParser.setCache(null); WebPageDownloader mockDownloader = Mockito.mock(WebPageDownloader.class); - when(mockDownloader.getFromNetwork(anyString(), anyString(), nullable(String.class))).thenReturn("<target><unk/></target>"); + when(mockDownloader.getFromNetwork(anyString(), anyString(), nullable(String.class))) + .thenReturn("<target><unk/></target>"); chemblParser.setWebPageDownloader(mockDownloader); chemblParser.getTargetFromId(new MiriamData(MiriamType.CHEMBL_TARGET, "water")); assertEquals(1, getWarnings().size()); @@ -842,7 +824,8 @@ public class ChEMBLParserTest extends AnnotationTestFunctions { // simulate problem with downloading WebPageDownloader mockDownloader = Mockito.mock(WebPageDownloader.class); - when(mockDownloader.getFromNetwork(anyString(), anyString(), nullable(String.class))).thenThrow(new IOException()); + when(mockDownloader.getFromNetwork(anyString(), anyString(), nullable(String.class))) + .thenThrow(new IOException()); chemblParser.setWebPageDownloader(mockDownloader); chemblParser.refreshCacheQuery("http://google.pl/"); fail("Exception expected"); @@ -866,7 +849,8 @@ public class ChEMBLParserTest extends AnnotationTestFunctions { // simulate problem with downloading WebPageDownloader mockDownloader = Mockito.mock(WebPageDownloader.class); - when(mockDownloader.getFromNetwork(anyString(), anyString(), nullable(String.class))).thenThrow(new IOException()); + when(mockDownloader.getFromNetwork(anyString(), anyString(), nullable(String.class))) + .thenThrow(new IOException()); chemblParser.setWebPageDownloader(mockDownloader); chemblParser.getDrugsByChemblTarget(new MiriamData()); @@ -920,7 +904,8 @@ public class ChEMBLParserTest extends AnnotationTestFunctions { // simulate problem with downloading WebPageDownloader mockDownloader = Mockito.mock(WebPageDownloader.class); - when(mockDownloader.getFromNetwork(anyString(), anyString(), nullable(String.class))).thenThrow(new IOException()); + when(mockDownloader.getFromNetwork(anyString(), anyString(), nullable(String.class))) + .thenThrow(new IOException()); chemblParser.setWebPageDownloader(mockDownloader); chemblParser.refreshCacheQuery(query); fail("Exception expected"); @@ -949,7 +934,8 @@ public class ChEMBLParserTest extends AnnotationTestFunctions { WebPageDownloader downloader = chemblParser.getWebPageDownloader(); try { WebPageDownloader mockDownloader = Mockito.mock(WebPageDownloader.class); - when(mockDownloader.getFromNetwork(anyString(), anyString(), nullable(String.class))).thenThrow(new IOException()); + when(mockDownloader.getFromNetwork(anyString(), anyString(), nullable(String.class))) + .thenThrow(new IOException()); chemblParser.setWebPageDownloader(mockDownloader); assertEquals(ExternalServiceStatusType.DOWN, chemblParser.getServiceStatus().getStatus()); } catch (Exception e) { @@ -984,9 +970,10 @@ public class ChEMBLParserTest extends AnnotationTestFunctions { WebPageDownloader mockDownloader = Mockito.mock(WebPageDownloader.class); // valid xml but with empty data - when(mockDownloader.getFromNetwork(anyString(), anyString(), nullable(String.class))).thenReturn("<response><molecules>" - + "<molecule><pref_name/><max_phase/><molecule_chembl_id/><molecule_synonyms/></molecule>" - + "</molecules><mechanisms/><molecule_forms/></response>"); + when(mockDownloader.getFromNetwork(anyString(), anyString(), nullable(String.class))) + .thenReturn("<response><molecules>" + + "<molecule><pref_name/><max_phase/><molecule_chembl_id/><molecule_synonyms/></molecule>" + + "</molecules><mechanisms/><molecule_forms/></response>"); chemblParser.setWebPageDownloader(mockDownloader); assertEquals(ExternalServiceStatusType.CHANGED, chemblParser.getServiceStatus().getStatus()); } catch (Exception e) { @@ -1043,7 +1030,8 @@ public class ChEMBLParserTest extends AnnotationTestFunctions { try { chemblParser.setCache(null); WebPageDownloader mockDownloader = Mockito.mock(WebPageDownloader.class); - when(mockDownloader.getFromNetwork(anyString(), anyString(), nullable(String.class))).thenThrow(new IOException()); + when(mockDownloader.getFromNetwork(anyString(), anyString(), nullable(String.class))) + .thenThrow(new IOException()); chemblParser.setWebPageDownloader(mockDownloader); chemblParser.getTargetsByDrugId(new MiriamData(MiriamType.CHEMBL_COMPOUND, "123")); fail("Exception expected"); @@ -1063,7 +1051,8 @@ public class ChEMBLParserTest extends AnnotationTestFunctions { try { chemblParser.setCache(null); WebPageDownloader mockDownloader = Mockito.mock(WebPageDownloader.class); - when(mockDownloader.getFromNetwork(anyString(), anyString(), nullable(String.class))).thenThrow(new IOException()); + when(mockDownloader.getFromNetwork(anyString(), anyString(), nullable(String.class))) + .thenThrow(new IOException()); chemblParser.setWebPageDownloader(mockDownloader); chemblParser.getDrugListByTarget(new MiriamData(MiriamType.UNIPROT, "O60391")); fail("Exception expected"); @@ -1165,7 +1154,8 @@ public class ChEMBLParserTest extends AnnotationTestFunctions { try { chemblParser.setCache(null); WebPageDownloader mockDownloader = Mockito.mock(WebPageDownloader.class); - when(mockDownloader.getFromNetwork(anyString(), anyString(), nullable(String.class))).thenThrow(new IOException()); + when(mockDownloader.getFromNetwork(anyString(), anyString(), nullable(String.class))) + .thenThrow(new IOException()); chemblParser.setWebPageDownloader(mockDownloader); chemblParser.getDrugById(new MiriamData(MiriamType.CHEMBL_COMPOUND, "")); fail("Exception expected"); @@ -1199,7 +1189,8 @@ public class ChEMBLParserTest extends AnnotationTestFunctions { try { chemblParser.setCache(null); WebPageDownloader mockDownloader = Mockito.mock(WebPageDownloader.class); - when(mockDownloader.getFromNetwork(anyString(), anyString(), nullable(String.class))).thenThrow(new IOException()); + when(mockDownloader.getFromNetwork(anyString(), anyString(), nullable(String.class))) + .thenThrow(new IOException()); chemblParser.setWebPageDownloader(mockDownloader); chemblParser.getTargetsForChildElements(new MiriamData()); fail("Exception expected"); @@ -1253,4 +1244,16 @@ public class ChEMBLParserTest extends AnnotationTestFunctions { } } + @Test + public void testFindDrugBryBrandName() throws Exception { + try { + Drug drug = chemblParser.findDrug("picato"); + assertNotNull(drug); + assertEquals("CHEMBL1863513", drug.getSources().get(0).getResource()); + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + } diff --git a/persist/src/main/resources/db/migration/13.1.4/V13.1.4.20190821__remove_chembl_cache.sql b/persist/src/main/resources/db/migration/13.1.4/V13.1.4.20190821__remove_chembl_cache.sql new file mode 100644 index 0000000000000000000000000000000000000000..6aea6b38443948a2f8999010f401d3a6f41cb16a --- /dev/null +++ b/persist/src/main/resources/db/migration/13.1.4/V13.1.4.20190821__remove_chembl_cache.sql @@ -0,0 +1 @@ +delete from cache_query_table where type in (select id from cache_type_table where class_name ='lcsb.mapviewer.annotation.services.ChEMBLParser'); diff --git a/service/src/main/java/lcsb/mapviewer/services/search/drug/DrugService.java b/service/src/main/java/lcsb/mapviewer/services/search/drug/DrugService.java index af680065bee15cff9a415671b649f1d7828f0407..073367df2bc8d263fdf3686dab6a3c141a76e7f6 100644 --- a/service/src/main/java/lcsb/mapviewer/services/search/drug/DrugService.java +++ b/service/src/main/java/lcsb/mapviewer/services/search/drug/DrugService.java @@ -1,11 +1,6 @@ package lcsb.mapviewer.services.search.drug; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; @@ -14,21 +9,14 @@ import org.springframework.transaction.annotation.Transactional; import lcsb.mapviewer.annotation.data.Drug; import lcsb.mapviewer.annotation.data.Target; -import lcsb.mapviewer.annotation.services.ChEMBLParser; -import lcsb.mapviewer.annotation.services.DrugSearchException; -import lcsb.mapviewer.annotation.services.DrugbankHTMLParser; +import lcsb.mapviewer.annotation.services.*; import lcsb.mapviewer.annotation.services.annotators.AnnotatorException; import lcsb.mapviewer.annotation.services.annotators.HgncAnnotator; import lcsb.mapviewer.common.IProgressUpdater; import lcsb.mapviewer.model.Project; -import lcsb.mapviewer.model.map.BioEntity; -import lcsb.mapviewer.model.map.MiriamData; -import lcsb.mapviewer.model.map.MiriamType; +import lcsb.mapviewer.model.map.*; import lcsb.mapviewer.model.map.model.Model; -import lcsb.mapviewer.model.map.species.Element; -import lcsb.mapviewer.model.map.species.Gene; -import lcsb.mapviewer.model.map.species.Protein; -import lcsb.mapviewer.model.map.species.Rna; +import lcsb.mapviewer.model.map.species.*; import lcsb.mapviewer.model.map.statistics.SearchType; import lcsb.mapviewer.services.interfaces.ISearchHistoryService; import lcsb.mapviewer.services.search.DbSearchCriteria; @@ -185,9 +173,15 @@ public class DrugService extends DbSearchService implements IDrugService { if (name.trim().equals("")) { return null; } + DrugAnnotation secondParser = chEMBLParser; Drug drug = null; try { drug = drugBankParser.findDrug(name); + + if (drug==null) { + drug = chEMBLParser.findDrug(name); + secondParser = drugBankParser; + } if (drug != null) { removeUnknownOrganisms(drug, searchCriteria.getOrganisms()); } @@ -201,13 +195,13 @@ public class DrugService extends DbSearchService implements IDrugService { // * search for name searchNames.add(name); if (drug != null && drug.getName() != null) { - // * search for name of a drug in drugbanke + // * search for name of a drug in drugbank searchNames.add(drug.getName()); // * search for all synonyms found in drugbank // searchNames.addAll(drug.getSynonyms()); } for (String string : searchNames) { - Drug drug2 = chEMBLParser.findDrug(string); + Drug drug2 = secondParser.findDrug(string); if (drug2 != null) { removeUnknownOrganisms(drug2, searchCriteria.getOrganisms()); // don't add drugs that were already found diff --git a/service/src/test/java/lcsb/mapviewer/services/search/drug/DrugServiceTest.java b/service/src/test/java/lcsb/mapviewer/services/search/drug/DrugServiceTest.java index c93d8dd442397f807d16878070eea849be05fb61..186339ba0c729e6c7c521e0774357c24d2fd8074 100644 --- a/service/src/test/java/lcsb/mapviewer/services/search/drug/DrugServiceTest.java +++ b/service/src/test/java/lcsb/mapviewer/services/search/drug/DrugServiceTest.java @@ -57,6 +57,17 @@ public class DrugServiceTest extends ServiceTestFunctions { } } + @Test + public void testGetIstodax() throws Exception { + try { + Drug drug = drugService.getByName("istodax", new DbSearchCriteria()); + assertEquals(2, drug.getSources().size()); + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + @Test public void testGetTargets() throws Exception { try {