From 54a99a1712d6f743a7b49245ddf494ecd9827273 Mon Sep 17 00:00:00 2001 From: David Hoksza <david.hoksza@uni.lu> Date: Tue, 6 Feb 2018 19:28:30 +0100 Subject: [PATCH] Passing annotator parameters from client to server --- .../annotation/services/ModelAnnotator.java | 4 +- .../services/annotators/KeggAnnotator.java | 146 +++++++++++------- .../annotators/BrendaAnnotatorTest.java | 8 - .../annotators/KeggAnnotatorTest.java | 81 +++++++++- .../js/gui/admin/ChooseAnnotatorsDialog.js | 6 +- .../model/user/UserAnnotationSchema.java | 13 +- .../services/impl/ProjectService.java | 11 +- 7 files changed, 186 insertions(+), 83 deletions(-) diff --git a/annotation/src/main/java/lcsb/mapviewer/annotation/services/ModelAnnotator.java b/annotation/src/main/java/lcsb/mapviewer/annotation/services/ModelAnnotator.java index bc053783e1..8328716508 100644 --- a/annotation/src/main/java/lcsb/mapviewer/annotation/services/ModelAnnotator.java +++ b/annotation/src/main/java/lcsb/mapviewer/annotation/services/ModelAnnotator.java @@ -363,9 +363,7 @@ public class ModelAnnotator { for (ElementAnnotator elementAnnotator : list) { try { - List<UserAnnotatorsParam> params = annotatorsParams.get(elementAnnotator.getClass()); - logger.debug("params"); - logger.debug(params); + List<UserAnnotatorsParam> params = annotatorsParams.get(elementAnnotator.getClass()); if (params != null) { elementAnnotator.annotateElement(element, params); } else { diff --git a/annotation/src/main/java/lcsb/mapviewer/annotation/services/annotators/KeggAnnotator.java b/annotation/src/main/java/lcsb/mapviewer/annotation/services/annotators/KeggAnnotator.java index 51654c7b6b..cbf8cee52c 100644 --- a/annotation/src/main/java/lcsb/mapviewer/annotation/services/annotators/KeggAnnotator.java +++ b/annotation/src/main/java/lcsb/mapviewer/annotation/services/annotators/KeggAnnotator.java @@ -4,6 +4,7 @@ package lcsb.mapviewer.annotation.services.annotators; import java.io.IOException; import java.util.Collection; import java.util.HashSet; +import java.util.List; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -27,6 +28,7 @@ import lcsb.mapviewer.model.map.species.GenericProtein; import lcsb.mapviewer.model.map.species.Protein; import lcsb.mapviewer.model.map.species.Rna; import lcsb.mapviewer.model.map.species.Species; +import lcsb.mapviewer.model.user.UserAnnotatorsParam; /** * This is a class that implements KEGG annotator which extract from KEGG @@ -48,6 +50,11 @@ public class KeggAnnotator extends ElementAnnotator implements IExternalService */ private Pattern pubmedMatcher = Pattern.compile("\\[PMID:(\\d+)\\]"); + /** + * Pattern used for finding ATH orghologs in KEGG GENE sectionpage. + */ + private Pattern athOrthologMatcher = Pattern.compile(" *ATH: (.*)"); + /** * Service used for annotation of entities using {@link MiriamType#TAIR_LOCUS TAIR}. @@ -73,14 +80,6 @@ public class KeggAnnotator extends ElementAnnotator implements IExternalService + " (GENE section in the KEGG enzyme record) should be imported." + " Currently ATH (Arabidopsis Thaliana) is supported."); this.addParameterDefinition(paramDef); - - this.addParameterDefinition(new AnnotatorParamDefinition("test string1", String.class, "test string1 comment")); - this.addParameterDefinition(new AnnotatorParamDefinition("test int1", Integer.class, "int1 comment")); - this.addParameterDefinition(new AnnotatorParamDefinition("test bool1", Boolean.class, "boolean comment")); - this.addParameterDefinition(new AnnotatorParamDefinition("test bool2", Boolean.class, "boolean comment 2")); - this.addParameterDefinition(new AnnotatorParamDefinition("test int2", Integer.class, "int2 comment")); - this.addParameterDefinition(new AnnotatorParamDefinition("test int3", Integer.class, "int3 comment")); - this.addParameterDefinition(new AnnotatorParamDefinition("test string2", String.class, "test string2 comment")); } @Override @@ -122,61 +121,66 @@ public class KeggAnnotator extends ElementAnnotator implements IExternalService @Override - public void annotateElement(BioEntity object) throws AnnotatorException { - if (isAnnotatable(object)) { + public void annotateElement(BioEntity object, List<UserAnnotatorsParam> params) throws AnnotatorException { + + if (!isAnnotatable(object)) { return; } - MiriamData mdTair = null; - for (MiriamData md : object.getMiriamData()) { - Class<?> annotator = md.getAnnotator(); - if (annotator == this.getClass()) { - //this annotator was already used - return; - } - else if (md.getDataType().equals(MiriamType.TAIR_LOCUS) && - (annotator == null ) ) { - mdTair = md; - } + MiriamData mdTair = null; + for (MiriamData md : object.getMiriamData()) { + Class<?> annotator = md.getAnnotator(); + if (annotator == this.getClass()) { + //this annotator was already used + return; } - - if (mdTair != null) tairAnnotator.annotateElement(object); - - MiriamData mdUniprot = null; - for (MiriamData md : object.getMiriamData()) { - if (md.getDataType().equals(MiriamType.UNIPROT) ) { - mdUniprot = md; - } + else if (md.getDataType().equals(MiriamType.TAIR_LOCUS) && + (annotator == null ) ) { + mdTair = md; + } + } + + if (mdTair != null) tairAnnotator.annotateElement(object); + + MiriamData mdUniprot = null; + for (MiriamData md : object.getMiriamData()) { + if (md.getDataType().equals(MiriamType.UNIPROT) ) { + mdUniprot = md; } - if (mdUniprot != null) uniprotAnnotator.annotateElement(object); - - Set<String> ecs = new HashSet<String>(); - for (MiriamData md : object.getMiriamData()) { - if (md.getDataType().equals(MiriamType.EC)) { - ecs.add(md.getResource()); - } + } + if (mdUniprot != null) uniprotAnnotator.annotateElement(object); + + Set<String> ecs = new HashSet<String>(); + for (MiriamData md : object.getMiriamData()) { + if (md.getDataType().equals(MiriamType.EC)) { + ecs.add(md.getResource()); } + } + + if (ecs.size() == 0) { + return; + } + + //annotate from KEGG + Set<MiriamData> annotations = new HashSet<MiriamData>(); + for (String ec: ecs) { - if (ecs.size() == 0) { - return; - } - - //annotate from KEGG - Set<MiriamData> annotations = new HashSet<MiriamData>(); - for (String ec: ecs) { - - String accessUrl = getKeggUrl(ec); - - try { - String pageContent = getWebPageContent(accessUrl); - annotations.addAll(parseKegg(pageContent)); - - } catch (WrongResponseCodeIOException exception) { - logger.warn("Cannot find kegg data for id: " + ec); - } catch (IOException exception) { - throw new AnnotatorException(exception); - } + String accessUrl = getKeggUrl(ec); + + try { + String pageContent = getWebPageContent(accessUrl); + annotations.addAll(parseKegg(pageContent, params)); + + } catch (WrongResponseCodeIOException exception) { + logger.warn("Cannot find kegg data for id: " + ec); + } catch (IOException exception) { + throw new AnnotatorException(exception); } - object.addMiriamData(annotations); - } + } + object.addMiriamData(annotations); + } + + @Override + public void annotateElement(BioEntity object) throws AnnotatorException { + this.annotateElement(object, null); } /** @@ -196,9 +200,16 @@ public class KeggAnnotator extends ElementAnnotator implements IExternalService * * @param pageContent * Kegg page - * @return {@link MiriamType#PUBMED}s found on the page + * @param params + * List of {@link UserAnnotatorsParam} to be used + * for parameterization. Should contain only at most + * one record with space separated KEGG organisms names. + * If the value has not been set by the user, + * null will be passed. + * @return + * {@link MiriamType#PUBMED}s found on the page */ - private Collection<MiriamData> parseKegg(String pageContent) { + private Collection<MiriamData> parseKegg(String pageContent, List<UserAnnotatorsParam> params) { //Retrieve Pubmeds Collection<MiriamData> result = new HashSet<MiriamData>(); @@ -208,6 +219,23 @@ public class KeggAnnotator extends ElementAnnotator implements IExternalService } //Retrieve homologous organisms based on parameterization + if (params != null) { + String[] keggOrgnismCodes = params.get(0).getParamValue().trim().split(" +"); + for (String code: keggOrgnismCodes) { + if (code.toUpperCase() != "ATH") { + logger.warn("KEGG annotator currently supports only ATH"); + } else { + m = athOrthologMatcher.matcher(pageContent); + if (m.find()) { + String[] tairCodes = m.group(1).trim().split(" "); + for (String tairCode: tairCodes) { + tairCode = tairCode.split("\\(")[0]; //some codes are in the form AT1G08510(FATB) + result.add(createMiriamData(MiriamType.TAIR_LOCUS, tairCode)); + } + } + } + } + } return result; } diff --git a/annotation/src/test/java/lcsb/mapviewer/annotation/services/annotators/BrendaAnnotatorTest.java b/annotation/src/test/java/lcsb/mapviewer/annotation/services/annotators/BrendaAnnotatorTest.java index a6db99a245..b26e1a87ca 100644 --- a/annotation/src/test/java/lcsb/mapviewer/annotation/services/annotators/BrendaAnnotatorTest.java +++ b/annotation/src/test/java/lcsb/mapviewer/annotation/services/annotators/BrendaAnnotatorTest.java @@ -2,23 +2,15 @@ package lcsb.mapviewer.annotation.services.annotators; import static org.junit.Assert.assertEquals; 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.Matchers.anyString; -import static org.mockito.Mockito.when; - -import java.util.Collection; -import java.io.IOException; import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; import lcsb.mapviewer.annotation.AnnotationTestFunctions; -import lcsb.mapviewer.annotation.cache.WebPageDownloader; import lcsb.mapviewer.annotation.services.ExternalServiceStatusType; import lcsb.mapviewer.common.exception.InvalidArgumentException; import lcsb.mapviewer.model.map.MiriamData; diff --git a/annotation/src/test/java/lcsb/mapviewer/annotation/services/annotators/KeggAnnotatorTest.java b/annotation/src/test/java/lcsb/mapviewer/annotation/services/annotators/KeggAnnotatorTest.java index a5a98a3a34..21e5e64b74 100644 --- a/annotation/src/test/java/lcsb/mapviewer/annotation/services/annotators/KeggAnnotatorTest.java +++ b/annotation/src/test/java/lcsb/mapviewer/annotation/services/annotators/KeggAnnotatorTest.java @@ -11,6 +11,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; +import java.util.List; import java.util.Set; import org.junit.After; @@ -27,6 +28,7 @@ import lcsb.mapviewer.model.map.MiriamData; import lcsb.mapviewer.model.map.MiriamType; import lcsb.mapviewer.model.map.species.GenericProtein; import lcsb.mapviewer.model.map.species.Species; +import lcsb.mapviewer.model.user.UserAnnotatorsParam; public class KeggAnnotatorTest extends AnnotationTestFunctions { @@ -71,7 +73,7 @@ public class KeggAnnotatorTest extends AnnotationTestFunctions { @Test - public void testAnnotateFromUniprot() throws Exception { + public void testAnnotateFromUniprotWithoutParams() throws Exception { try { Species protein = new GenericProtein("id"); @@ -89,6 +91,82 @@ public class KeggAnnotatorTest extends AnnotationTestFunctions { } } + @Test + public void testAnnotateFromUniprotWithParams() throws Exception { + try { + + Species protein = new GenericProtein("id"); + protein.setName("bla"); + protein.addMiriamData(new MiriamData(MiriamType.UNIPROT, "Q42561")); + + UserAnnotatorsParam ap = new UserAnnotatorsParam(String.class, "KEGG organism identifier", "ATH"); + List<UserAnnotatorsParam> aps = new ArrayList<>(); + aps.add(ap); + keggAnnotator.annotateElement(protein, aps); + + int cntTairs = 0; + for (MiriamData md : protein.getMiriamData()) { + if (md.getDataType().equals(MiriamType.TAIR_LOCUS)) { + cntTairs++; + } + } + + assertTrue("Invalid number of TAIR annotators from KEGG", cntTairs == 3); + + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + + @Test + public void testAnnotateFromUniprotWithWrongParams1() throws Exception { + try { + + Species protein = new GenericProtein("id"); + protein.setName("bla"); + protein.addMiriamData(new MiriamData(MiriamType.UNIPROT, "Q42561")); + + UserAnnotatorsParam ap = new UserAnnotatorsParam(String.class, "XXX", "XXX"); + List<UserAnnotatorsParam> aps = new ArrayList<>(); + aps.add(ap); + keggAnnotator.annotateElement(protein, aps); + + assertEquals("There should be warning about unsupported parameter", 1, getWarnings().size()); + + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + + @Test + public void testAnnotateFromUniprotWithWrongParams2() throws Exception { + try { + + Species protein = new GenericProtein("id"); + protein.setName("bla"); + protein.addMiriamData(new MiriamData(MiriamType.UNIPROT, "Q42561")); + List<UserAnnotatorsParam> aps = new ArrayList<>(); + aps.add(new UserAnnotatorsParam(String.class, "KEGG organism identifier", "ATH XXX")); + keggAnnotator.annotateElement(protein, aps); + + int cntTairs = 0; + for (MiriamData md : protein.getMiriamData()) { + if (md.getDataType().equals(MiriamType.TAIR_LOCUS)) { + cntTairs++; + } + } + + assertTrue("Invalid number of TAIR annotators from KEGG", cntTairs == 3); + assertEquals("There should be warning about unsupported parameter", 1, getWarnings().size()); + + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + @Test public void testAnnotateFromEc() throws Exception { try { @@ -101,7 +179,6 @@ public class KeggAnnotatorTest extends AnnotationTestFunctions { Evaluate_3_1_2_14(protein); - } catch (Exception e) { e.printStackTrace(); throw e; diff --git a/frontend-js/src/main/js/gui/admin/ChooseAnnotatorsDialog.js b/frontend-js/src/main/js/gui/admin/ChooseAnnotatorsDialog.js index b5c8cd9563..30e9ae6405 100644 --- a/frontend-js/src/main/js/gui/admin/ChooseAnnotatorsDialog.js +++ b/frontend-js/src/main/js/gui/admin/ChooseAnnotatorsDialog.js @@ -65,7 +65,8 @@ function onChangeParameterValue(element, user){ var annotatorsParams = {}; annotatorsParams[annotatorClassName] = {}; - annotatorsParams[annotatorClassName][name] = element.value; + if (element.type == 'checkbox') annotatorsParams[annotatorClassName][name] = element.checked.toString(); + else annotatorsParams[annotatorClassName][name] = element.value; data.setAnnotatorsParameters(annotatorsParams); return ServerConnector.updateUserPreferences({user: user, preferences: data}).then(null, GuiConnector.alert); @@ -95,6 +96,7 @@ ChooseAnnotatorsDialog.prototype.setElementType = function (elementType) { var selectedAnnotators = user.getPreferences().getElementAnnotators(elementType.className); var existingAnnotatorsParameters = user.getPreferences().getAnnotatorsParameters(); + for (var i = 0; i < annotators.length; i++) { var annotator = annotators[i]; var selected = false; @@ -157,12 +159,14 @@ ChooseAnnotatorsDialog.prototype.setElementType = function (elementType) { inputType: "number", onchange: function(){return onChangeParameterValue(this, user);} }); + if (existingParamValue) paramValue.value = existingParamValue; } else if (param.type.indexOf("Boolean") >= 0) { paramValue = Functions.createElement({ type: "input", inputType: "checkbox", onchange: function(){return onChangeParameterValue(this, user);} }); + paramValue.checked = (existingParamValue && existingParamValue === 'true'); } else { throw new InvalidAlgorithmError("Unknown annotator parameter type"); } diff --git a/model/src/main/java/lcsb/mapviewer/model/user/UserAnnotationSchema.java b/model/src/main/java/lcsb/mapviewer/model/user/UserAnnotationSchema.java index 398f339169..40c1fec0c2 100644 --- a/model/src/main/java/lcsb/mapviewer/model/user/UserAnnotationSchema.java +++ b/model/src/main/java/lcsb/mapviewer/model/user/UserAnnotationSchema.java @@ -248,17 +248,12 @@ public class UserAnnotationSchema implements Serializable { if (params.getAnnotatorClassName().equals(ap.getAnnotatorClassName()) && params.getParamName().equals(ap.getParamName())) { this.annotatorsParams.get(i).setParamValue(ap.getParamValue()); - } else { - ap.setAnnotationSchema(this); - this.annotatorsParams.add(ap); + return; } } - - if (this.annotatorsParams.size() == 0) { - ap.setAnnotationSchema(this); - this.annotatorsParams.add(ap); - } - + + ap.setAnnotationSchema(this); + this.annotatorsParams.add(ap); } /** diff --git a/service/src/main/java/lcsb/mapviewer/services/impl/ProjectService.java b/service/src/main/java/lcsb/mapviewer/services/impl/ProjectService.java index c8409f670f..8d7ff171de 100644 --- a/service/src/main/java/lcsb/mapviewer/services/impl/ProjectService.java +++ b/service/src/main/java/lcsb/mapviewer/services/impl/ProjectService.java @@ -1469,7 +1469,16 @@ public class ProjectService implements IProjectService { dbUser.setAnnotationSchema(annotationSchema); } - return annotationSchema.getAnnotatorsParams(); + /* + * Hibernate lazy loads collections so each element needs to be accessed + * to be loaded now or otherwise the data might not be available + * when accessed because the session might not be available at that time. + */ + List<UserAnnotatorsParam> aps = new ArrayList<>(); + for (UserAnnotatorsParam ap: annotationSchema.getAnnotatorsParams()){ + aps.add(ap); + } + return aps; } /** -- GitLab