Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add options to connect to database for c. annotation #13

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,13 @@ Installation instructions:
- Do you want to install any cache files (y/n)? -> y, install GRCh37 or GRCh38 cache
- Do you want to install any FASTA files (y/n)? -> y, install GRCh37 or GRCh38 FASTA
- Do you want to install any plugins (y/n)? -> n

## Connect an Ensembl database

In order to annotate c. alterations, you must connect to a MySQL database. For an example of connecting to Ensembl's public database, you would use the defaults
show in [application.properties](target/classes/application.properties).

However, Ensembl does not recommend connecting to their public database (as it is very slow), so it is recommended to set up a local copy of their database by following
the [instructions](https://useast.ensembl.org/info/docs/webcode/mirror/install/ensembl-data.html) on the Ensembl website.

**IMPORTANT: Make sure the ensembl-vep docker image, the cache files, and the MySQL database are all using the same version.**
100 changes: 100 additions & 0 deletions src/main/java/org/genomenexus/vep_wrapper/VepHgvsController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package org.genomenexus.vep_wrapper;

import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.List;

import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;

@RestController
@CrossOrigin(origins="*")
@RequestMapping(value= "/vep/human/hgvsc")
@ConditionalOnProperty(
value = "database.enabled",
havingValue = "true"
)
@Api(tags = "vep-hgvs-controller", description = "VEP HGVS Controller")
public class VepHgvsController {

@Autowired
private VepRunner vepRunner;

@RequestMapping(value = "/{hgvsc}",
method = RequestMethod.GET,
produces = "application/json")
@ApiOperation(value = "Retrieves VEP results for single c. variant specified in hgvs syntax (https://ensembl.org/info/docs/tools/vep/vep_formats.html)",
nickname = "fetchVepHgvscAnnotationByGET")
public void getVepHgvscAnnotation(
@ApiParam(value="ENST00000618231.3:c.9G>C", required=true)
@PathVariable
String hgvsc,
@ApiParam("Maximum time (in seconds) to let VEP construct a response (0 = no limit)")
@RequestParam(defaultValue = "0")
Integer responseTimeout,
HttpServletResponse response) {
OutputStream out = null;
try {
out = response.getOutputStream();
response.setContentType("application/json");
vepRunner.run(Arrays.asList(hgvsc), false, responseTimeout, out, true);
} catch (IOException | InterruptedException | VepLaunchFailureException e) {
e.printStackTrace();
// TODO: throw and handle errors with global exception handler
} finally {
try {
response.flushBuffer();
} catch (Throwable e) {
e.printStackTrace();
// TODO: throw and handle errors with global exception handler
}
}
}

@RequestMapping(value = "/",
method = RequestMethod.POST)
@ApiOperation(value = "Retrieves VEP results for multiple c. variants specified in hgvs syntax (https://ensembl.org/info/docs/tools/vep/vep_formats.html)",
nickname = "fetchVepHgvscAnnotationsByPOST")
public void fetchVepHgvscAnnotationsPOST(
@ApiParam(value = "List of variants in ENSEMBL hgvsc format. For example:\n" +
"[\"ENST00000618231.3:c.9G>C\", \"ENST00000471631.1:c.28_33delTCGCGG\"]",
required = true)
@RequestBody
List<String> hgvscStrings,
@ApiParam("Maximum time (in seconds) to let VEP construct a response (0 = no limit)")
@RequestParam(defaultValue = "0")
Integer responseTimeout,
HttpServletResponse response) {
OutputStream out = null;
try {
out = response.getOutputStream();
response.setContentType("application/json");
vepRunner.run(hgvscStrings, true, responseTimeout, out, true);
} catch (IOException | InterruptedException | VepLaunchFailureException e) {
e.printStackTrace();
// TODO: throw and handle errors with global exception handler
} finally {
try {
response.flushBuffer();
} catch (Throwable e) {
e.printStackTrace();
// TODO: throw and handle errors with global exception handler
}
}
return;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@

@RestController
@CrossOrigin(origins="*") // allow all cross-domain requests
@RequestMapping(value= "/")
@Api(tags = "vep-controller", description = "VEP Controller")
public class VepController {
@RequestMapping(value= "/vep/human/region")
@Api(tags = "vep-region-controller", description = "VEP Region Controller")
public class VepRegionController {

@Autowired
private VepRunner vepRunner;

@RequestMapping(value = "/vep/human/region/{region}/{allele}",
@RequestMapping(value = "/{region}/{allele}",
method = RequestMethod.GET,
produces = "application/json")
@ApiOperation(value = "Retrieves VEP results for single variant specified in region syntax (https://ensembl.org/info/docs/tools/vep/vep_formats.html)",
Expand All @@ -44,7 +44,7 @@ public void getVepAnnotation(
try {
out = response.getOutputStream();
response.setContentType("application/json");
vepRunner.run(Arrays.asList(region + "/" + allele), false, responseTimeout, out);
vepRunner.run(Arrays.asList(region + "/" + allele), false, responseTimeout, out, false);
} catch (IOException | InterruptedException | VepLaunchFailureException e) {
e.printStackTrace();
// TODO: throw and handle errors with global exception handler
Expand All @@ -58,7 +58,7 @@ public void getVepAnnotation(
}
}

@RequestMapping(value = "/vep/human/region",
@RequestMapping(value = "/",
method = RequestMethod.POST)
@ApiOperation(value = "Retrieves VEP annotations for multiple variants specified in region syntax (https://ensembl.org/info/docs/tools/vep/vep_formats.html)",
nickname = "fetchVepAnnotationByRegionsPOST")
Expand All @@ -83,7 +83,7 @@ public void fetchVepAnnotationByRegionsPOST(
try {
out = response.getOutputStream();
response.setContentType("application/json");
vepRunner.run(regions, true, responseTimeout, out);
vepRunner.run(regions, true, responseTimeout, out, false);
} catch (IOException | InterruptedException | VepLaunchFailureException e) {
e.printStackTrace();
// TODO: throw and handle errors with global exception handler
Expand All @@ -97,5 +97,4 @@ public void fetchVepAnnotationByRegionsPOST(
}
return;
}

}
83 changes: 72 additions & 11 deletions src/main/java/org/genomenexus/vep_wrapper/VepRunner.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,33 @@ public class VepRunner {
private String vepAssembly;

// Path is relative to the VEP_WORK_DIRECTORY_PATH
@Value("${vep.fastaFileRelativePath:homo_sapiens/98_GRCh37/Homo_sapiens.GRCh37.75.dna.primary_assembly.fa.gz}")
@Value("${vep.fastaFileRelativePath:homo_sapiens/112_GRCh37/Homo_sapiens.GRCh37.dna.primary_assembly.fa.gz}")
private String vepFastaFileRelativePath;

@Value("${database.grch37.host}")
private String grch37DatabaseHost;

@Value("${database.grch37.port}")
private String grch37DatabasePort;

@Value("${database.grch37.user}")
private String grch37DatabaseUser;

@Value("${database.grch37.password}")
private String grch37DatabasePassword;

@Value("${database.grch38.host}")
private String grch38DatabaseHost;

@Value("${database.grch38.port}")
private String grch38DatabasePort;

@Value("${database.grch38.user}")
private String grch38DatabaseUser;

@Value("${database.grch38.password}")
private String grch38DatabasePassword;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's use similar setup here as for the genome nexus backend (one vep per genome nexus instance), so maybe this can be simplified to database.host database.port etc


private Path vepFastaFilePath;
@Autowired
private void setVepFastaFilePath() {
Expand All @@ -64,21 +88,21 @@ private void createTmpDirIfNecessary() throws IOException {
}

/**
* Create a file containing the regions received in the input query.
* Write the user supplied regions from the "regions" argument to an output file.
* CAUTION : this function does not sort the regions into chromosomal order. The
* Create a file containing the variants received in the input query.
* Write the user supplied variants from the "variants" argument to an output file.
* CAUTION : this function does not sort the variants into chromosomal order. The
* VEP command line tool is very slow when the input is not sorted. It is expected
* that users of the VepRunner will always send requests that have been pre-sorted.
*
* @param regions - the regions as passed by the user
* @param variants - the variants as passed by the user
* @param vepInputFile - the file to be written
* @return sum of two operands

**/
private void constructFileForVepProcessing(List<String> regions, Path vepInputFile) throws IOException {
private void constructFileForVepProcessing(List<String> variants, Path vepInputFile) throws IOException {
try (PrintWriter out = new PrintWriter(Files.newBufferedWriter(vepInputFile))) {
for (String region : regions) {
out.println(region);
for (String variant : variants) {
out.println(variant);
}
out.close();
} catch (IOException e) {
Expand Down Expand Up @@ -111,7 +135,7 @@ public boolean timeIsExpired(Instant timeToKillProcess) {
return Instant.now().isAfter(timeToKillProcess);
}

public void run(List<String> regions, Boolean convertToListJSON, Integer responseTimeout, OutputStream responseOut)
public void run(List<String> variants, Boolean convertToListJSON, Integer responseTimeout, OutputStream responseOut, boolean useDatabase)
throws IOException, InterruptedException, VepLaunchFailureException {

printWithTimestamp("Running vep");
Expand All @@ -120,7 +144,43 @@ public void run(List<String> regions, Boolean convertToListJSON, Integer respons
Path constructedInputFile = createTempFileForVepInput();

// get vep parameters (use -Dvep.params to change)
String vepParameters = System.getProperty("vep.params", String.join(" ",
String vepParameters;
if (useDatabase) {
String databaseHost = "";
String databasePort = "";
String databaseUser = "";
String databasePassword = "";

if (vepAssembly.equals("GRCh38")) {
databaseHost = grch38DatabaseHost;
databasePort = grch38DatabasePort;
databaseUser = grch38DatabaseUser;
databasePassword = grch38DatabasePassword;
} else {
databaseHost = grch37DatabaseHost;
databasePort = grch37DatabasePort;
databaseUser = grch37DatabaseUser;
databasePassword = grch37DatabasePassword;
}

vepParameters = System.getProperty("vep.params", String.join(" ",
"--database",
"--host " + databaseHost,
"--user " + databaseUser,
"--password " + databasePassword,
"--port " + databasePort,
"--everything",
"--hgvsg",
"--xref_refseq",
"--format hgvs",
"--fork " + vepForkCount,
"--fasta " + vepFastaFilePath,
"--json",
"-i " + constructedInputFile,
"-o STDOUT",
"--no_stats"));
} else {
vepParameters = System.getProperty("vep.params", String.join(" ",
"--cache",
"--offline",
"--everything",
Expand All @@ -134,6 +194,7 @@ public void run(List<String> regions, Boolean convertToListJSON, Integer respons
"-i " + constructedInputFile,
"-o STDOUT",
"--no_stats"));
}

// build command
List<String> commandElements = new ArrayList<String>();
Expand All @@ -143,7 +204,7 @@ public void run(List<String> regions, Boolean convertToListJSON, Integer respons
}

printWithTimestamp("writing constructed input file");
constructFileForVepProcessing(regions, constructedInputFile);
constructFileForVepProcessing(variants, constructedInputFile);

printWithTimestamp("processing requests");
printWithTimestamp("process command elements: " + commandElements);
Expand Down
Empty file.
12 changes: 12 additions & 0 deletions src/main/resources/application.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
database:
enabled: true
grch37:
host: host.docker.internal
port: 3306
user: root
password: AlphaMale1987!!
grch38:
host: host.docker.internal
port: 3307
user: root
password: my-secret-pw