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

Merge branch '641-list-of-suggested-drugs-doesn-t-work-on-pdmap' into 'master'

Resolve "list of suggested drugs doesn't work on pdmap"

Closes #641

See merge request minerva/core!1041
parents 3c682d53 91f3571f
minerva (15.0.0~alpha.2) stable; urgency=medium
* Feature removal: old connection to drugBank is removed and replaced with
new Data-API interface that closely check license compliance
* Small improvement: when typing drug, list of autocomplete drugs should be
available limited to the drugs targetting something on the map (#641)
* Small improvement: data not compliant with database constraints (for
instance too long species identifiers) will be automatically adjust instead
of crashing project upload (#1041)
......@@ -10,6 +14,8 @@ minerva (15.0.0~alpha.2) stable; urgency=medium
* Bug fix: procseing sbgn file with render information was breaking sometimes
(regresion 15.0.0~alpha.1, #1020)
-- Piotr Gawron <piotr.gawron@uni.lu> Wed, 22 Jan 2020 13:00:00 +0200
minerva (15.0.0~alpha.1) stable; urgency=medium
* Feature removal: when uploading complex map with submap there is no
possibility to change submap name (#947)
......
......@@ -59,7 +59,7 @@
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-jcl</artifactId>
<version>${log4j-jcl-version}</version>
</dependency>
<dependency>
......@@ -122,8 +122,8 @@
<artifactId>txw2</artifactId>
</exclusion>
<exclusion>
<groupId>org.jvnet.staxex</groupId>
<artifactId>stax-ex</artifactId>
<groupId>org.jvnet.staxex</groupId>
<artifactId>stax-ex</artifactId>
</exclusion>
</exclusions>
</dependency>
......@@ -225,11 +225,42 @@
</exclusions>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>${commons-codec.version}</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>${commons-codec.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.maven/maven-artifact -->
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-artifact</artifactId>
<version>3.6.3</version>
<exclusions>
<exclusion>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-validator/commons-validator -->
<dependency>
<groupId>commons-validator</groupId>
<artifactId>commons-validator</artifactId>
<version>${commons-validator.version}</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
<exclusion>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- mockito used for testing -->
<dependency>
......@@ -246,5 +277,10 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
</dependencies>
</project>
\ No newline at end of file
......@@ -124,6 +124,12 @@ public abstract class CachableInterface {
}
}
protected final void removeCacheValue(String key) {
if (cache != null) {
cache.removeByQuery(key, getCacheType());
}
}
/**
* @return the cacheType
* @see #cacheType
......
......@@ -270,15 +270,6 @@ public class Drug implements Serializable, TargettingStructure {
return targets;
}
/**
* @param targets
* the targets to set
* @see #targets
*/
public void setTargets(List<Target> targets) {
this.targets = targets;
}
/**
* @param sources
* the sources to set
......@@ -333,4 +324,12 @@ public class Drug implements Serializable, TargettingStructure {
}
}
public void addBrandNames(List<String> brandNames) {
this.brandNames.addAll(brandNames);
}
public void addSynonyms(List<String> synonyms) {
this.synonyms.addAll(synonyms);
}
}
\ No newline at end of file
......@@ -5,7 +5,6 @@ import org.apache.logging.log4j.Marker;
import lcsb.mapviewer.model.LogMarker;
import lcsb.mapviewer.model.ProjectLogEntryType;
import lcsb.mapviewer.model.map.BioEntity;
import lcsb.mapviewer.modelutils.map.ElementUtils;
/**
* Defines annotation problem with element when there are no annotations for the
......
......@@ -8,7 +8,6 @@ import lcsb.mapviewer.common.exception.InvalidArgumentException;
import lcsb.mapviewer.model.LogMarker;
import lcsb.mapviewer.model.ProjectLogEntryType;
import lcsb.mapviewer.model.map.*;
import lcsb.mapviewer.modelutils.map.ElementUtils;
/**
* Defines problem with element annotation when there are some required
......
package lcsb.mapviewer.annotation.services.dapi;
public class DapiConnectionException extends Exception {
/**
*
*/
private static final long serialVersionUID = 1L;
private Integer statusCode;
public DapiConnectionException(String string, int statusCode) {
super(string);
this.statusCode = statusCode;
}
public DapiConnectionException(String string, Exception e) {
super(string, e);
}
public Integer getStatusCode() {
return statusCode;
}
}
package lcsb.mapviewer.annotation.services.dapi;
import java.util.List;
import lcsb.mapviewer.annotation.services.dapi.dto.ReleaseDto;
import lcsb.mapviewer.annotation.services.dapi.dto.UserDto;
public interface DapiConnector {
void login() throws DapiConnectionException;
String getLatestReleaseAvailable(String databaseName) throws DapiConnectionException;
String getLatestReleaseUrl(String databaseName) throws DapiConnectionException;
String getAuthenticatedContent(String string) throws DapiConnectionException;
boolean isValidConnection();
boolean isAuthenticated();
void resetConnection();
List<String> getDatabases() throws DapiConnectionException;
List<ReleaseDto> getReleases(String database) throws DapiConnectionException;
boolean isReleaseAccepted(String database, ReleaseDto release) throws DapiConnectionException;
void acceptRelease(String database, String release) throws DapiConnectionException;
void registerUser(UserDto user) throws DapiConnectionException;
}
package lcsb.mapviewer.annotation.services.dapi;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.*;
import java.util.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import org.springframework.stereotype.Service;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.JsonArray;
import com.google.gson.JsonParser;
import lcsb.mapviewer.annotation.cache.CachableInterface;
import lcsb.mapviewer.annotation.services.dapi.dto.*;
import lcsb.mapviewer.model.user.ConfigurationElementType;
import lcsb.mapviewer.persist.dao.ConfigurationDao;
@Service
public class DapiConnectorImpl extends CachableInterface implements DapiConnector {
private static Logger logger = LogManager.getLogger();
private static final String DAPI_DOMAIN = "dapi.lcsb.uni.lu";
private static final String DAPI_BASE_URL = "http://" + DAPI_DOMAIN + "/api/";
private ConfigurationDao configurationDao;
private ObjectMapper objectMapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,
false);
private Calendar lastAuthentication;
static {
CookieManager cookieManager = new CookieManager();
CookieHandler.setDefault(cookieManager);
}
public DapiConnectorImpl(ConfigurationDao configurationDao) {
super(DapiConnectorImpl.class);
this.configurationDao = configurationDao;
}
@Override
public String getLatestReleaseAvailable(String databaseName) throws DapiConnectionException {
try {
String content = getAuthenticatedContent(DAPI_BASE_URL + "database/" + databaseName + "/releases/?size=1000",
false);
Set<String> releases = new HashSet<>();
ListReleaseDto result = objectMapper.readValue(content, ListReleaseDto.class);
for (ReleaseDto release : result.getContent()) {
releases.add(release.getName());
}
String userDataContent = getAuthenticatedContent(DAPI_BASE_URL + "users/" + getDapiLogin(), false);
JsonArray array = new JsonParser()
.parse(userDataContent)
.getAsJsonObject()
.get("acceptedReleaseLicenses")
.getAsJsonArray();
Set<String> acceptedReleases = new HashSet<>();
for (int i = 0; i < array.size(); i++) {
String release = array.get(i).getAsJsonObject().get("release").getAsJsonObject().get("name").getAsString();
if (releases.contains(release)) {
acceptedReleases.add(release);
}
}
return getLatestVersion(acceptedReleases);
} catch (IOException e) {
throw new DapiConnectionException("Problem with accessing dapi data", e);
}
}
public String getDapiLogin() {
return configurationDao.getValueByType(ConfigurationElementType.DAPI_LOGIN);
}
String getLatestVersion(Collection<String> acceptedReleases) {
List<DefaultArtifactVersion> versions = new ArrayList<>();
for (String string : acceptedReleases) {
versions.add(new DefaultArtifactVersion(string));
}
Collections.sort(versions);
if (versions.size() == 0) {
return null;
}
return versions.get(versions.size() - 1).toString();
}
private String getAuthenticatedContent(String string, boolean fromCache) throws DapiConnectionException {
if (!isAuthenticated()) {
login();
}
try {
if (!fromCache) {
super.removeCacheValue(string);
}
if (getCacheValue(string) == null) {
lastAuthentication = Calendar.getInstance();
}
return getWebPageContent(string);
} catch (IOException e) {
throw new DapiConnectionException("Problem with accessing dapi data", e);
}
}
@Override
public String getLatestReleaseUrl(String databaseName) throws DapiConnectionException {
String release = getLatestReleaseAvailable(databaseName);
if (release == null) {
return null;
}
return DAPI_BASE_URL + "database/" + databaseName + "/releases/" + getLatestReleaseAvailable(databaseName) + "/";
}
@Override
public String getAuthenticatedContent(String string) throws DapiConnectionException {
return getAuthenticatedContent(string, true);
}
@Override
public boolean isAuthenticated() {
Calendar nowMinus10Minutes = Calendar.getInstance();
nowMinus10Minutes.add(Calendar.MINUTE, -10);
if (lastAuthentication != null && lastAuthentication.after(nowMinus10Minutes)) {
return true;
} else {
try {
getWebPageDownloader().getFromNetwork(DAPI_BASE_URL + "users/isAuthenticated");
return true;
} catch (IOException e) {
return false;
}
}
}
@Override
public void login() throws DapiConnectionException {
try {
login(getDapiLogin(), getDapiPassword());
lastAuthentication = Calendar.getInstance();
} catch (IOException e) {
CookieManager cookieManager = (CookieManager) CookieHandler.getDefault();
cookieManager.getCookieStore().removeAll();
throw new DapiConnectionException("Problem with connection to DAPI server", e);
}
}
public String getDapiPassword() {
return configurationDao.getValueByType(ConfigurationElementType.DAPI_PASSWORD);
}
void login(String login, String password)
throws MalformedURLException, IOException, ProtocolException, DapiConnectionException {
String data = "login=" + URLEncoder.encode(login, "UTF-8") + "&password=" + URLEncoder.encode(password, "UTF-8");
URL url = new URL(DAPI_BASE_URL + "doLogin");
HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
urlConn.addRequestProperty("User-Agent", "minerva-framework");
urlConn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
urlConn.setRequestMethod("POST");
urlConn.setDoOutput(true);
DataOutputStream wr = new DataOutputStream(urlConn.getOutputStream());
wr.writeBytes(data);
wr.close();
urlConn.connect();
int code = urlConn.getResponseCode();
if (code != HttpURLConnection.HTTP_OK) {
throw new DapiConnectionException("Problem with connection to dapi.", code);
}
}
@Override
public boolean isValidConnection() {
if (getDapiLogin() == null || getDapiLogin().isEmpty() || getDapiPassword() == null
|| getDapiPassword().isEmpty()) {
return false;
}
if (isAuthenticated()) {
return true;
}
try {
login();
} catch (DapiConnectionException e) {
logger.warn("Invalid credentials");
return false;
}
return isAuthenticated();
}
@Override
public void resetConnection() {
CookieManager cookieManager = (CookieManager) CookieHandler.getDefault();
List<HttpCookie> cookies = new ArrayList<>();
for (HttpCookie cookie : cookieManager.getCookieStore().getCookies()) {
if (Objects.equals(cookie.getDomain(), DAPI_DOMAIN)) {
cookies.add(cookie);
}
}
for (HttpCookie cookie : cookies) {
cookieManager.getCookieStore().remove(null, cookie);
}
lastAuthentication = null;
}
@Override
public List<String> getDatabases() throws DapiConnectionException {
try {
List<String> result = new ArrayList<>();
String url = DAPI_BASE_URL + "database/";
String content = getWebPageDownloader().getFromNetwork(url);
JsonArray array = new JsonParser()
.parse(content)
.getAsJsonObject()
.get("content")
.getAsJsonArray();
for (int i = 0; i < array.size(); i++) {
result.add(array.get(i).getAsJsonObject().get("name").getAsString());
}
return result;
} catch (IOException e) {
throw new DapiConnectionException("Problem with accessing dapi", e);
}
}
@Override
public List<ReleaseDto> getReleases(String database) throws DapiConnectionException {
try {
String url = DAPI_BASE_URL + "database/" + database + "/releases/";
String content = getWebPageDownloader().getFromNetwork(url);
ListReleaseDto result = objectMapper.readValue(content, ListReleaseDto.class);
return result.getContent();
} catch (IOException e) {
throw new DapiConnectionException("Problem with accessing dapi", e);
}
}
@Override
public boolean isReleaseAccepted(String database, ReleaseDto release) throws DapiConnectionException {
String userDataContent = getAuthenticatedContent(DAPI_BASE_URL + "users/" + getDapiLogin(), false);
JsonArray array = new JsonParser()
.parse(userDataContent)
.getAsJsonObject()
.get("acceptedReleaseLicenses")
.getAsJsonArray();
for (int i = 0; i < array.size(); i++) {
String releaseName = array.get(i).getAsJsonObject().get("release").getAsJsonObject().get("name").getAsString();
if (releaseName.equals(release.getName())) {
return true;
}
}
return false;
}
@Override
public void acceptRelease(String database, String release) throws DapiConnectionException {
if (!isAuthenticated()) {
login();
}
try {
getWebPageDownloader().getFromNetwork(
DAPI_BASE_URL + "database/" + database + "/releases/" + release + ":acceptLicense", "POST", "");
} catch (IOException e) {
throw new DapiConnectionException("Problem with accessing dapi", e);
}
}
@Override
public void registerUser(UserDto user) throws DapiConnectionException {
try {
URL url = new URL(DAPI_BASE_URL + "users/" + user.getLogin());
HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
urlConn.addRequestProperty("User-Agent", "minerva-framework");
urlConn.setRequestProperty("Content-Type", "application/json; utf-8");
urlConn.setRequestMethod("POST");
urlConn.setDoOutput(true);
DataOutputStream wr = new DataOutputStream(urlConn.getOutputStream());
wr.writeBytes(objectMapper.writeValueAsString(user));
wr.close();
urlConn.connect();
int code = urlConn.getResponseCode();
if (code != HttpURLConnection.HTTP_OK) {
throw new DapiConnectionException(
"Problem with connection to dapi. ", code);
}
} catch (IOException e) {
throw new DapiConnectionException("Problem with connection to dapi.", e);
}
}
}
package lcsb.mapviewer.annotation.services.dapi;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import lcsb.mapviewer.annotation.cache.GeneralCacheInterface;
import lcsb.mapviewer.annotation.data.Drug;
import lcsb.mapviewer.annotation.data.Target;
import lcsb.mapviewer.annotation.services.*;
import lcsb.mapviewer.annotation.services.annotators.AnnotatorException;
import lcsb.mapviewer.annotation.services.annotators.HgncAnnotator;
import lcsb.mapviewer.annotation.services.dapi.dto.*;
import lcsb.mapviewer.common.exception.InvalidArgumentException;
import lcsb.mapviewer.model.map.MiriamData;
import lcsb.mapviewer.model.map.MiriamType;
@Service
public class DrugBankParser extends DrugAnnotation implements IExternalService {
public static final String DAPI_DATABASE_NAME = "DrugBank";
private static Logger logger = LogManager.getLogger();
private DapiConnector dapiConnector;
private HgncAnnotator hgncAnnotator;
private ChemicalEntityDtoConverter chemicalEntityDtoConverter;
ObjectMapper objectMapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,
false);
@Autowired