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 bc053783e1b3b2bfa1fe975d5e132a9bfd1ad12d..8328716508788f665daeea66528fa8dc4bcd0530 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 51654c7b6b91da4148a2f7ee8a85108b650e7936..cbf8cee52c7a6389442a61baa88629cc9d9c8af3 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 a6db99a245ddbcbb729f4b6f53ddcb5dbf40f107..b26e1a87ca1bbe1cc6a5c9ec09f725d0a3662eee 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 a5a98a3a342f33001763231997a010b5eb5e511a..21e5e64b7491890bc978d801de0edacbb09353c2 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 035c2bb12a5e963ec2a8aef78dea1ad03b3ba2cf..d1d4737232e2827d478d753e503be66240473269 100644 --- a/frontend-js/src/main/js/gui/admin/ChooseAnnotatorsDialog.js +++ b/frontend-js/src/main/js/gui/admin/ChooseAnnotatorsDialog.js @@ -63,7 +63,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); @@ -93,6 +94,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; @@ -155,12 +157,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 398f339169ef5fd4b8c9a0c6588e7f7f791edb53..40c1fec0c2b9e6612e3e835d0aaeceb7cb11bc5b 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 dbc7b67f57587dae89cdcecff5446a064884fdd1..c23b0c884bf1f4f6e40f9e1790026853b4332eda 100644 --- a/service/src/main/java/lcsb/mapviewer/services/impl/ProjectService.java +++ b/service/src/main/java/lcsb/mapviewer/services/impl/ProjectService.java @@ -1461,7 +1461,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; } /**