Commit fb7c8012 authored by Piotr Gawron's avatar Piotr Gawron
Browse files

GO connector uses new API

parent 2543a6d2
package lcsb.mapviewer.annotation.services.annotators;
import java.io.IOException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.w3c.dom.Node;
import com.google.gson.Gson;
import com.google.gson.internal.StringMap;
import lcsb.mapviewer.annotation.cache.GeneralCacheInterface;
import lcsb.mapviewer.annotation.cache.SourceNotAvailable;
......@@ -20,14 +21,13 @@ import lcsb.mapviewer.annotation.services.ExternalServiceStatusType;
import lcsb.mapviewer.annotation.services.IExternalService;
import lcsb.mapviewer.annotation.services.MiriamConnector;
import lcsb.mapviewer.common.exception.InvalidArgumentException;
import lcsb.mapviewer.common.exception.InvalidXmlSchemaException;
import lcsb.mapviewer.model.map.BioEntity;
import lcsb.mapviewer.model.map.MiriamData;
import lcsb.mapviewer.model.map.MiriamRelationType;
import lcsb.mapviewer.model.map.MiriamType;
import lcsb.mapviewer.model.map.compartment.Compartment;
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.Phenotype;
import lcsb.mapviewer.modelutils.map.ElementUtils;
......@@ -39,194 +39,194 @@ import lcsb.mapviewer.modelutils.map.ElementUtils;
*/
public class GoAnnotator extends ElementAnnotator implements IExternalService {
/**
* Prefix string used for marking the query in database as query by go term.
*/
static final String GO_TERM_CACHE_PREFIX = "GO_TERM: ";
/**
* Default class logger.
*/
private Logger logger = Logger.getLogger(GoAnnotator.class);
/**
* Connector used for accessing data from miriam registry.
*/
@Autowired
private MiriamConnector mc;
/**
* Object that allows to serialize {@link Go} elements into xml string and
* deserialize xml into {@link Go} objects.
*/
private XmlSerializer<Go> goSerializer;
@Override
public String refreshCacheQuery(Object query) throws SourceNotAvailable {
String result = null;
try {
if (query instanceof String) {
String name = (String) query;
if (name.startsWith(GO_TERM_CACHE_PREFIX)) {
String term = name.substring(GO_TERM_CACHE_PREFIX.length());
MiriamData md = new MiriamData(MiriamRelationType.BQ_BIOL_IS_DESCRIBED_BY, MiriamType.GO, term);
result = goSerializer.objectToString(getGoElement(md));
} else if (name.startsWith("http")) {
result = getWebPageContent(name);
} else {
throw new InvalidArgumentException("Don't know what to do with query: " + query);
}
} else {
throw new InvalidArgumentException("Don't know what to do with class: " + query.getClass());
}
} catch (IOException | GoSearchException e) {
throw new SourceNotAvailable(e);
}
return result;
}
/**
* Default constructor. Initializes structures used for transforming
* {@link Go} from/to xml.
*/
public GoAnnotator() {
super(GoAnnotator.class, new Class[] { Phenotype.class, Compartment.class, Complex.class }, true);
goSerializer = new XmlSerializer<>(Go.class);
}
@Override
public void annotateElement(BioEntity object) throws AnnotatorException {
if (isAnnotatable(object)) {
MiriamData goTerm = null;
for (MiriamData md : object.getMiriamData()) {
if (md.getDataType().equals(MiriamType.GO)) {
goTerm = md;
}
}
if (goTerm == null) {
return;
}
try {
Go go = getGoElement(goTerm);
String commonName = go.getCommonName();
setFullName((Element) object, commonName, new ElementUtils().getElementTag(object, this));
String description = go.getDescription();
setDescription(object, description);
} catch (GoSearchException e) {
throw new AnnotatorException(e);
}
}
}
/**
* Returns go entry from the Gene Ontology database for the goTerm
* (identifier).
*
* @param md
* {@link MiriamData} object referencing to entry in GO database
* @return entry in Gene Ontology database
* @throws GoSearchException
* thrown when there is a problem with accessing data in go database
*/
protected Go getGoElement(MiriamData md) throws GoSearchException {
Go result = goSerializer.xmlToObject(getCacheNode(GO_TERM_CACHE_PREFIX + md.getResource()));
if (result != null) {
return result;
} else {
result = new Go();
}
String accessUrl = "https://www.ebi.ac.uk/QuickGO-Old/GTerm?id=" + md.getResource() + "&format=oboxml";
try {
String tmp = getWebPageContent(accessUrl);
Node xml = getXmlDocumentFromString(tmp.toString());
// XPath is here used to locate parts of an XML document
XPath xpath = XPathFactory.newInstance().newXPath();
// Locate the term name and print it out
String commonName = xpath.compile("/obo/term/name").evaluate(xml);
String description = xpath.compile("/obo/term/def/defstr").evaluate(xml);
result.setCommonName(commonName);
result.setDescription(description);
result.setGoTerm(md.getResource());
setCacheValue(GO_TERM_CACHE_PREFIX + md.getResource(), goSerializer.objectToString(result));
return result;
} catch (IOException e) {
throw new GoSearchException("Problem with accesing go database", e);
} catch (InvalidXmlSchemaException | XPathExpressionException e) {
throw new GoSearchException("Data from go db have invalid format", e);
}
}
@Override
public ExternalServiceStatus getServiceStatus() {
ExternalServiceStatus status = new ExternalServiceStatus(getCommonName(), getUrl());
GeneralCacheInterface cacheCopy = getCache();
this.setCache(null);
try {
Compartment compartmentAlias = new Compartment("some_id");
compartmentAlias.addMiriamData(new MiriamData(MiriamRelationType.BQ_BIOL_IS_DESCRIBED_BY, MiriamType.GO, "GO:0046902"));
annotateElement(compartmentAlias);
if (compartmentAlias.getFullName() == null || compartmentAlias.getFullName().equals("")) {
status.setStatus(ExternalServiceStatusType.CHANGED);
} else if (compartmentAlias.getNotes() == null || compartmentAlias.getNotes().equals("")) {
status.setStatus(ExternalServiceStatusType.CHANGED);
} else {
status.setStatus(ExternalServiceStatusType.OK);
}
} catch (Exception e) {
logger.error("GeneOntology is down", e);
status.setStatus(ExternalServiceStatusType.DOWN);
}
this.setCache(cacheCopy);
return status;
}
/**
* @return the mc
* @see #mc
*/
public MiriamConnector getMc() {
return mc;
}
/**
* @param mc
* the mc to set
* @see #mc
*/
public void setMc(MiriamConnector mc) {
this.mc = mc;
}
@Override
public String getCommonName() {
return MiriamType.GO.getCommonName();
}
@Override
public String getUrl() {
return MiriamType.GO.getDbHomepage();
}
@Override
protected WebPageDownloader getWebPageDownloader() {
return super.getWebPageDownloader();
}
@Override
protected void setWebPageDownloader(WebPageDownloader webPageDownloader) {
super.setWebPageDownloader(webPageDownloader);
}
/**
* Prefix string used for marking the query in database as query by go term.
*/
static final String GO_TERM_CACHE_PREFIX = "GO_TERM: ";
/**
* Default class logger.
*/
private Logger logger = Logger.getLogger(GoAnnotator.class);
/**
* Connector used for accessing data from miriam registry.
*/
@Autowired
private MiriamConnector mc;
/**
* Object that allows to serialize {@link Go} elements into xml string and
* deserialize xml into {@link Go} objects.
*/
private XmlSerializer<Go> goSerializer;
@Override
public String refreshCacheQuery(Object query) throws SourceNotAvailable {
String result = null;
try {
if (query instanceof String) {
String name = (String) query;
if (name.startsWith(GO_TERM_CACHE_PREFIX)) {
String term = name.substring(GO_TERM_CACHE_PREFIX.length());
MiriamData md = new MiriamData(MiriamRelationType.BQ_BIOL_IS_DESCRIBED_BY, MiriamType.GO, term);
result = goSerializer.objectToString(getGoElement(md));
} else if (name.startsWith("http")) {
result = getWebPageContent(name);
} else {
throw new InvalidArgumentException("Don't know what to do with query: " + query);
}
} else {
throw new InvalidArgumentException("Don't know what to do with class: " + query.getClass());
}
} catch (IOException | GoSearchException e) {
throw new SourceNotAvailable(e);
}
return result;
}
/**
* Default constructor. Initializes structures used for transforming {@link Go}
* from/to xml.
*/
public GoAnnotator() {
super(GoAnnotator.class, new Class[] { Phenotype.class, Compartment.class, Complex.class }, true);
goSerializer = new XmlSerializer<>(Go.class);
}
@Override
public void annotateElement(BioEntity object) throws AnnotatorException {
if (isAnnotatable(object)) {
MiriamData goTerm = null;
for (MiriamData md : object.getMiriamData()) {
if (md.getDataType().equals(MiriamType.GO)) {
goTerm = md;
}
}
if (goTerm == null) {
return;
}
try {
Go go = getGoElement(goTerm);
if (go != null) {
setFullName((Element) object, go.getCommonName(), new ElementUtils().getElementTag(object, this));
setDescription(object, go.getDescription());
}
} catch (GoSearchException e) {
throw new AnnotatorException(e);
}
}
}
/**
* Returns go entry from the Gene Ontology database for the goTerm (identifier).
*
* @param md
* {@link MiriamData} object referencing to entry in GO database
* @return entry in Gene Ontology database
* @throws GoSearchException
* thrown when there is a problem with accessing data in go database
*/
protected Go getGoElement(MiriamData md) throws GoSearchException {
Go result = goSerializer.xmlToObject(getCacheNode(GO_TERM_CACHE_PREFIX + md.getResource()));
if (result != null) {
return result;
} else {
result = new Go();
}
String accessUrl = "https://www.ebi.ac.uk/QuickGO/services/ontology/go/terms/" + md.getResource();
try {
String page = getWebPageContent(accessUrl);
Gson gson = new Gson();
Map<?, ?> gsonObject = (Map<?, ?>) gson.fromJson(page, HashMap.class);
Double hits = (Double) gsonObject.get("numberOfHits");
if (hits < 1) {
return null;
}
List<?> objects = (List<?>) gsonObject.get("results");
StringMap<?> object = (StringMap<?>) objects.get(0);
result.setGoTerm((String) object.get("id"));
result.setCommonName((String) object.get("name"));
StringMap<?> descr = (StringMap<?>) object.get("definition");
if (descr != null) {
result.setDescription((String) descr.get("text"));
}
return result;
} catch (Exception e) {
throw new GoSearchException("Problem with accesing go database", e);
}
}
@Override
public ExternalServiceStatus getServiceStatus() {
ExternalServiceStatus status = new ExternalServiceStatus(getCommonName(), getUrl());
GeneralCacheInterface cacheCopy = getCache();
this.setCache(null);
try {
Compartment compartment = new Compartment("some_id");
compartment.addMiriamData(new MiriamData(MiriamType.GO, "GO:0046902"));
annotateElement(compartment);
if (compartment.getFullName() == null || compartment.getFullName().equals("")) {
status.setStatus(ExternalServiceStatusType.CHANGED);
} else if (compartment.getNotes() == null || compartment.getNotes().equals("")) {
status.setStatus(ExternalServiceStatusType.CHANGED);
} else {
status.setStatus(ExternalServiceStatusType.OK);
}
} catch (Exception e) {
logger.error("GeneOntology is down", e);
status.setStatus(ExternalServiceStatusType.DOWN);
}
this.setCache(cacheCopy);
return status;
}
/**
* @return the mc
* @see #mc
*/
public MiriamConnector getMc() {
return mc;
}
/**
* @param mc
* the mc to set
* @see #mc
*/
public void setMc(MiriamConnector mc) {
this.mc = mc;
}
@Override
public String getCommonName() {
return MiriamType.GO.getCommonName();
}
@Override
public String getUrl() {
return MiriamType.GO.getDbHomepage();
}
@Override
protected WebPageDownloader getWebPageDownloader() {
return super.getWebPageDownloader();
}
@Override
protected void setWebPageDownloader(WebPageDownloader webPageDownloader) {
super.setWebPageDownloader(webPageDownloader);
}
}
......@@ -31,208 +31,212 @@ import lcsb.mapviewer.model.map.MiriamType;
import lcsb.mapviewer.model.map.compartment.Compartment;
public class GoAnnotatorTest extends AnnotationTestFunctions {
Logger logger = Logger.getLogger(GoAnnotatorTest.class);
@Autowired
GoAnnotator goAnnotator;
@Autowired
private PermanentDatabaseLevelCacheInterface cache;
@Before
public void setUp() throws Exception {
}
@After
public void tearDown() throws Exception {
}
@Test
public void testContent() throws Exception {
try {
Compartment compartmentAlias = new Compartment("id");
compartmentAlias.addMiriamData(new MiriamData(MiriamRelationType.BQ_BIOL_IS_DESCRIBED_BY, MiriamType.GO, "GO:0046902"));
goAnnotator.annotateElement(compartmentAlias);
assertFalse(compartmentAlias.getFullName().equals(""));
assertFalse(compartmentAlias.getNotes().equals(""));
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
@Test
public void testAnnotate() throws Exception {
try {
MiriamData md = new MiriamData(MiriamRelationType.BQ_BIOL_IS_DESCRIBED_BY, MiriamType.GO, "GO:0042644");
Go go = goAnnotator.getGoElement(md);
assertEquals("GO:0042644", go.getGoTerm());
assertNotNull(go.getCommonName());
assertNotNull(go.getDescription());
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
@Test
public void testAnnotateWhenProblemWithNetworkResponse() throws Exception {
try {
MiriamData md = new MiriamData(MiriamRelationType.BQ_BIOL_IS_DESCRIBED_BY, MiriamType.GO, "GO:0042644");
GoAnnotator annotator = new GoAnnotator();
annotator.setMc(goAnnotator.getMc());
WebPageDownloader downloader = Mockito.mock(WebPageDownloader.class);
when(downloader.getFromNetwork(anyString())).thenReturn("");
annotator.setWebPageDownloader(downloader);
annotator.getGoElement(md);
fail("Exception expected");
} catch (GoSearchException e) {
assertTrue(e.getMessage().contains("Data from go db have invalid format"));
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
@Test(timeout = 15000)
public void testCachableInterface() throws Exception {
String query = GoAnnotator.GO_TERM_CACHE_PREFIX + "GO:0046902";
String newRes = "hello";
try {
waitForRefreshCacheQueueToEmpty();
cache.setCachedQuery(query, goAnnotator.getCacheType(), newRes);
cache.invalidateByQuery(query, goAnnotator.getCacheType());
waitForRefreshCacheQueueToEmpty();
String res = cache.getStringByQuery(query, goAnnotator.getCacheType());
assertNotNull(res);
assertFalse("Value wasn't refreshed from db", newRes.equals(res));
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
@Test
public void testRefreshCacheQueryNotAvailable() throws Exception {
WebPageDownloader downloader = goAnnotator.getWebPageDownloader();
GeneralCacheInterface originalCache = goAnnotator.getCache();
try {
// exclude first cached value
goAnnotator.setCache(null);
WebPageDownloader mockDownloader = Mockito.mock(WebPageDownloader.class);
when(mockDownloader.getFromNetwork(anyString())).thenThrow(new IOException());
goAnnotator.setWebPageDownloader(mockDownloader);
goAnnotator.refreshCacheQuery("http://google.pl/");
fail("Exception expected");
} catch (SourceNotAvailable e) {
} catch (Exception e) {
e.printStackTrace();
throw e;
} finally {
goAnnotator.setWebPageDownloader(downloader);
goAnnotator.setCache(originalCache);
}
}
@Test
public void testRefreshInvalidCacheQuery() throws Exception {
try {
goAnnotator.refreshCacheQuery("invalid_query");
fail("Exception expected");
} catch (InvalidArgumentException e) {
assertTrue(e.getMessage().contains("Don't know what to do"));
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
@Test
public void testRefreshInvalidCacheQuery2() throws Exception {
try {
goAnnotator.refreshCacheQuery(new Object());
fail("Exception expected");