/* * Copyright 2015-2016 OpenCB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.opencb.opencga.server.rest; import io.swagger.annotations.*; import org.apache.commons.lang3.StringUtils; import org.opencb.biodata.models.alignment.Alignment; import org.opencb.biodata.models.core.Region; import org.opencb.biodata.models.variant.Variant; import org.opencb.commons.datastore.core.ObjectMap; import org.opencb.commons.datastore.core.Query; import org.opencb.commons.datastore.core.QueryOptions; import org.opencb.commons.datastore.core.QueryResult; import org.opencb.opencga.catalog.db.api.FileDBAdaptor; import org.opencb.opencga.catalog.db.api.StudyDBAdaptor; import org.opencb.opencga.catalog.exceptions.CatalogException; import org.opencb.opencga.catalog.managers.AbstractManager; import org.opencb.opencga.catalog.models.*; import org.opencb.opencga.catalog.models.summaries.StudySummary; import org.opencb.opencga.catalog.utils.FileScanner; import org.opencb.opencga.core.exception.VersionException; import org.opencb.opencga.storage.core.alignment.AlignmentDBAdaptor; import org.opencb.opencga.storage.core.alignment.AlignmentStorageEngine; import org.opencb.opencga.storage.core.exceptions.StorageEngineException; import org.opencb.opencga.storage.core.manager.variant.VariantStorageManager; import org.opencb.opencga.storage.core.manager.variant.operations.StorageOperation; import org.opencb.opencga.storage.core.variant.adaptors.VariantDBAdaptor; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.*; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; import java.io.IOException; import java.net.URI; import java.util.*; import java.util.stream.Collectors; @Path("/{version}/studies") @Produces(MediaType.APPLICATION_JSON) @Api(value = "Studies", position = 3, description = "Methods for working with 'studies' endpoint") public class StudyWSServer extends OpenCGAWSServer { public StudyWSServer(@Context UriInfo uriInfo, @Context HttpServletRequest httpServletRequest) throws IOException, VersionException { super(uriInfo, httpServletRequest); } @GET @Path("/create") @ApiOperation(value = "Create a new study [WARNING]", response = Study.class, notes = "WARNING: the usage of this web service is discouraged, please use the POST version instead. Be aware that this is web " + "service is not tested and this can be deprecated in a future version.") public Response createStudy(@ApiParam(value = "Project id or alias", required = true) @QueryParam("projectId") String projectIdStr, @ApiParam(value = "Study name", required = true) @QueryParam("name") String name, @ApiParam(value = "Study alias", required = true) @QueryParam("alias") String alias, @ApiParam(value = "Study type") @DefaultValue("CASE_CONTROL") @QueryParam("type") Study.Type type, @ApiParam(value = "Study description") @QueryParam("description") String description) { try { long projectId = catalogManager.getProjectId(projectIdStr, sessionId); QueryResult queryResult = catalogManager.createStudy(projectId, name, alias, type, description, sessionId); queryResult.setId("Create study in " + projectIdStr); return createOkResponse(queryResult); } catch (Exception e) { return createErrorResponse(e); } } @POST @Path("/create") @Consumes(MediaType.APPLICATION_JSON) @ApiOperation(value = "Create a new study", response = Study.class, notes = "Wont't accept files, jobs, experiments, samples.<br>" + "Will accept: acl, uri, cohorts, datasets.<br>" + "<ul>" + "<il><b>id</b>, <b>lastModified</b> and <b>size</b> parameters will be ignored.<br></il>" + "<il><b>type</b> accepted values: [<b>'CASE_CONTROL', 'CASE_SET', 'CONTROL_SET', 'FAMILY', 'PAIRED', 'TRIO'</b>].<br>" + "</il><ul>") public Response createStudyPOST(@ApiParam(value = "Project id or alias", required = true) @QueryParam("projectId") String projectIdStr, @ApiParam(value="study", required = true) Study study) { long projectId; try { String userId = catalogManager.getUserManager().getId(sessionId); projectId = catalogManager.getProjectManager().getId(userId, projectIdStr); } catch (Exception e) { return createErrorResponse(e); } logger.debug("study = {}", study); try { return createOkResponse(catalogManager.createStudy(projectId, study.getName(), study.getAlias(), study.getType(), study.getCreationDate(), study.getDescription(), new Status(), study.getCipher(), null, null, null, study.getStats(), study.getAttributes(), queryOptions, sessionId)); } catch (Exception e) { return createErrorResponse(e); } } @GET @Path("/search") @ApiOperation(value = "Search studies", response = Study[].class) @ApiImplicitParams({ @ApiImplicitParam(name = "include", value = "Set which fields are included in the response, e.g.: name,alias...", dataType = "string", paramType = "query"), @ApiImplicitParam(name = "exclude", value = "Set which fields are excluded in the response, e.g.: name,alias...", dataType = "string", paramType = "query"), @ApiImplicitParam(name = "limit", value = "Max number of results to be returned.", dataType = "integer", paramType = "query"), @ApiImplicitParam(name = "skip", value = "Number of results to be skipped.", dataType = "integer", paramType = "query"), @ApiImplicitParam(name = "count", value = "Get a count of the number of results obtained. Deactivated by default.", dataType = "boolean", paramType = "query") }) public Response getAllStudies(@ApiParam(value = "Project id or alias", required = true) @QueryParam("projectId") String projectId, @ApiParam(value = "Study name") @QueryParam("name") String name, @ApiParam(value = "Study alias") @QueryParam("alias") String alias, @ApiParam(value = "Type of study: CASE_CONTROL, CASE_SET...") @QueryParam("type") String type, @ApiParam(value = "Creation date") @QueryParam("creationDate") String creationDate, @ApiParam(value = "Status") @QueryParam("status") String status, @ApiParam(value = "Attributes") @QueryParam("attributes") String attributes, @Deprecated @ApiParam(value = "Numerical attributes") @QueryParam("nattributes") String nattributes, @Deprecated @ApiParam(value = "Boolean attributes") @QueryParam("battributes") boolean battributes, @ApiParam(value = "Skip count", defaultValue = "false") @QueryParam("skipCount") boolean skipCount) { try { queryOptions.put(QueryOptions.SKIP_COUNT, skipCount); if (projectId != null) { query.put(StudyDBAdaptor.QueryParams.PROJECT_ID.key(), catalogManager.getProjectId(projectId, sessionId)); } QueryResult<Study> queryResult = catalogManager.getAllStudies(query, queryOptions, sessionId); return createOkResponse(queryResult); } catch (Exception e) { return createErrorResponse(e); } } @POST @Path("/search") @Consumes(MediaType.APPLICATION_JSON) @ApiOperation(value = "Search studies", position = 2, hidden = true, response = Study[].class) @ApiImplicitParams({ @ApiImplicitParam(name = "include", value = "Fields included in the response, whole JSON path must be provided", example = "name,attributes", dataType = "string", paramType = "query"), @ApiImplicitParam(name = "exclude", value = "Fields excluded in the response, whole JSON path must be provided", example = "id,status", dataType = "string", paramType = "query"), @ApiImplicitParam(name = "limit", value = "Number of results to be returned in the queries", dataType = "integer", paramType = "query"), @ApiImplicitParam(name = "skip", value = "Number of results to skip in the queries", dataType = "integer", paramType = "query"), @ApiImplicitParam(name = "count", value = "Total number of results", dataType = "boolean", paramType = "query") }) public Response getAllStudiesByPost(@ApiParam(value="studies", required = true) Query query, @ApiParam(value = "Skip count", defaultValue = "false") @QueryParam("skipCount") boolean skipCount) { try { queryOptions.put(QueryOptions.SKIP_COUNT, skipCount); QueryResult<Study> queryResult = catalogManager.getAllStudies(query, queryOptions, sessionId); return createOkResponse(queryResult); } catch (Exception e) { return createErrorResponse(e); } } @GET @Path("/{study}/update") @ApiOperation(value = "Update some study attributes [WARNING]", response = Study.class, notes = "WARNING: the usage of this web service is discouraged, please use the POST version instead. Be aware that this is web service " + "is not tested and this can be deprecated in a future version.") public Response update(@ApiParam(value = "Study [[user@]project:]study where study and project can be either the id or alias", required = true) @PathParam("study") String studyStr, @ApiParam(value = "Study name") @QueryParam("name") String name, @ApiParam(value = "Study alias") @QueryParam("alias") String alias, @ApiParam(value = "Study type") @QueryParam("type") String type, @ApiParam(value = "Study description") @QueryParam("description") String description, @ApiParam(value = "Study attributes") @QueryParam("attributes") String attributes, @ApiParam(value = "Study stats") @QueryParam("stats") String stats) throws IOException { try { ObjectMap params = new ObjectMap(); params.putIfNotNull(StudyDBAdaptor.QueryParams.NAME.key(), name); params.putIfNotNull(StudyDBAdaptor.QueryParams.ALIAS.key(), alias); params.putIfNotNull(StudyDBAdaptor.QueryParams.TYPE.key(), type); params.putIfNotNull(StudyDBAdaptor.QueryParams.DESCRIPTION.key(), description); params.putIfNotNull(StudyDBAdaptor.QueryParams.ATTRIBUTES.key(), attributes); params.putIfNotNull(StudyDBAdaptor.QueryParams.STATS.key(), stats); logger.debug(params.toJson()); long studyId = catalogManager.getStudyId(studyStr, sessionId); QueryResult result = catalogManager.modifyStudy(studyId, params, sessionId); return createOkResponse(result); } catch (Exception e) { return createErrorResponse(e); } } public static class UpdateStudy { public String name; public Study.Type type; public String description; public Map<String, Object> stats; public Map<String, Object> attributes; } @POST @Path("/{study}/update") @Consumes(MediaType.APPLICATION_JSON) @ApiOperation(value = "Update some study attributes") public Response updateByPost(@ApiParam(value = "Study [[user@]project:]study where study and project can be either the id or alias", required = true) @PathParam("study") String studyStr, @ApiParam(value = "JSON containing the params to be updated.", required = true) UpdateStudy updateParams) { try { long studyId = catalogManager.getStudyId(studyStr, sessionId); QueryResult queryResult = catalogManager .modifyStudy(studyId, new ObjectMap(jsonObjectMapper.writeValueAsString(updateParams)), sessionId); return createOkResponse(queryResult); } catch (Exception e) { return createErrorResponse(e); } } @GET @Path("/{study}/delete") @ApiOperation(value = "Delete a study [PENDING]", response = Study.class) public Response delete(@ApiParam(value = "Study [[user@]project:]study where study and project can be either the id or alias", required = true) @PathParam("study") String studyStr) { return createOkResponse("PENDING"); } @GET @Path("/{study}/info") @ApiOperation(value = "Fetch study information", response = Study[].class) @ApiImplicitParams({ @ApiImplicitParam(name = "include", value = "Set which fields are included in the response, e.g.: name,alias...", dataType = "string", paramType = "query"), @ApiImplicitParam(name = "exclude", value = "Set which fields are excluded in the response, e.g.: name,alias...", dataType = "string", paramType = "query") }) public Response info(@ApiParam(value = "Study [[user@]project:]study where study and project can be either the id or alias", required = true) @PathParam("study") String studyStr) { try { List<QueryResult<Study>> queryResults = new LinkedList<>(); List<Long> studyIds = catalogManager.getStudyIds(studyStr, sessionId); for (Long studyId : studyIds) { queryResults.add(catalogManager.getStudy(studyId, queryOptions, sessionId)); } return createOkResponse(queryResults); } catch (Exception e) { return createErrorResponse(e); } } @GET @Path("/{study}/summary") @ApiOperation(value = "Fetch study information plus some basic stats", notes = "Fetch study information plus some basic stats such as" + " the number of files, samples, cohorts...") public Response summary(@ApiParam(value = "Study [[user@]project:]study where study and project can be either the id or alias", required = true) @PathParam("study") String studyStr) { try { List<Long> studyIds = catalogManager.getStudyIds(studyStr, sessionId); List<QueryResult<StudySummary>> queryResults = new LinkedList<>(); for (Long studyId : studyIds) { queryResults.add(catalogManager.getStudySummary(studyId, sessionId, queryOptions)); } return createOkResponse(queryResults); } catch (Exception e) { return createErrorResponse(e); } } @GET @Path("/{study}/files") @ApiOperation(value = "Fetch files in study", response = File[].class) @ApiImplicitParams({ @ApiImplicitParam(name = "include", value = "Set which fields are included in the response, e.g.: name,alias...", dataType = "string", paramType = "query"), @ApiImplicitParam(name = "exclude", value = "Set which fields are excluded in the response, e.g.: name,alias...", dataType = "string", paramType = "query"), @ApiImplicitParam(name = "limit", value = "Max number of results to be returned.", dataType = "integer", paramType = "query"), @ApiImplicitParam(name = "skip", value = "Number of results to be skipped.", dataType = "integer", paramType = "query"), @ApiImplicitParam(name = "count", value = "Get a count of the number of results obtained. Deactivated by default.", dataType = "boolean", paramType = "query") }) public Response getAllFiles(@ApiParam(value = "Study [[user@]project:]study where study and project can be either the id or alias", required = true) @PathParam("study") String studyStr, @ApiParam(value = "File id") @QueryParam("id") String id, @ApiParam(value = "File name") @QueryParam("name") String name, @ApiParam(value = "File path") @QueryParam("path") String path, @ApiParam(value = "File type (FILE or DIRECTORY)") @QueryParam("type") String type, @ApiParam(value = "Comma separated list of bioformat values. For existing Bioformats see files/bioformats") @QueryParam("bioformat") String bioformat, @ApiParam(value = "Comma separated list of format values. For existing Formats see files/formats") @QueryParam("format") String formats, @ApiParam(value = "File status") @QueryParam("status") File.FileStatus status, @ApiParam(value = "Directory where the files will be looked for") @QueryParam("directory") String directory, @ApiParam(value = "Creation date of the file") @QueryParam("creationDate") String creationDate, @ApiParam(value = "Last modification date of the file") @QueryParam("modificationDate") String modificationDate, @ApiParam(value = "File description") @QueryParam("description") String description, @ApiParam(value = "File size") @QueryParam("size") Long size, @ApiParam(value = "List of sample ids associated with the files") @QueryParam("sampleIds") String sampleIds, @ApiParam(value = "Job id that generated the file") @QueryParam("jobId") String jobId, @ApiParam(value = "Attributes") @QueryParam("attributes") String attributes, @ApiParam(value = "Numerical attributes") @QueryParam("nattributes") String nattributes) { try { long studyId = catalogManager.getStudyId(studyStr, sessionId); QueryResult queryResult = catalogManager.getAllFiles(studyId, query, queryOptions, sessionId); return createOkResponse(queryResult); } catch (Exception e) { return createErrorResponse(e); } } @GET @Path("/{study}/samples") @ApiOperation(value = "Fetch samples in study", response = Sample[].class) @ApiImplicitParams({ @ApiImplicitParam(name = "include", value = "Set which fields are included in the response, e.g.: name,alias...", dataType = "string", paramType = "query"), @ApiImplicitParam(name = "exclude", value = "Set which fields are excluded in the response, e.g.: name,alias...", dataType = "string", paramType = "query"), @ApiImplicitParam(name = "limit", value = "Max number of results to be returned.", dataType = "integer", paramType = "query"), @ApiImplicitParam(name = "skip", value = "Number of results to be skipped.", dataType = "integer", paramType = "query"), @ApiImplicitParam(name = "count", value = "Get a count of the number of results obtained. Deactivated by default.", dataType = "boolean", paramType = "query") }) public Response getAllSamples(@ApiParam(value = "Study [[user@]project:]study where study and project can be either the id or alias", required = true) @PathParam("study") String studyStr, @ApiParam(value = "Sample name") @QueryParam("name") String name, @Deprecated @ApiParam(value = "source", hidden = true) @QueryParam("source") String source, @ApiParam(value = "individualId") @QueryParam("individualId") String individualId, @ApiParam(value = "annotationSetName") @QueryParam("annotationSetName") String annotationSetName, @ApiParam(value = "variableSetId") @QueryParam("variableSetId") String variableSetId, @ApiParam(value = "annotation") @QueryParam("annotation") String annotation) { try { long studyId = catalogManager.getStudyId(studyStr, sessionId); QueryResult queryResult = catalogManager.getAllSamples(studyId, query, queryOptions, sessionId); return createOkResponse(queryResult); } catch (Exception e) { return createErrorResponse(e); } } @GET @Path("/{study}/jobs") @ApiOperation(value = "Return filtered jobs in study [PENDING]", position = 9, notes = "Currently it returns all the jobs in the study." + " No filters are being used yet.", response = Job[].class) @ApiImplicitParams({ @ApiImplicitParam(name = "include", value = "Fields included in the response, whole JSON path must be provided", example = "name,attributes", dataType = "string", paramType = "query"), @ApiImplicitParam(name = "exclude", value = "Fields excluded in the response, whole JSON path must be provided", example = "id,status", dataType = "string", paramType = "query"), @ApiImplicitParam(name = "limit", value = "Number of results to be returned in the queries", dataType = "integer", paramType = "query"), @ApiImplicitParam(name = "skip", value = "Number of results to skip in the queries", dataType = "integer", paramType = "query"), @ApiImplicitParam(name = "count", value = "Total number of results", dataType = "boolean", paramType = "query") }) public Response getAllJobs(@ApiParam(value = "Study [[user@]project:]study where study and project can be either the id or alias", required = true) @PathParam("study") String studyStr, @ApiParam(value = "name") @DefaultValue("") @QueryParam("name") String name, @ApiParam(value = "tool name") @DefaultValue("") @QueryParam("toolName") String tool, @ApiParam(value = "status") @DefaultValue("") @QueryParam("status") String status, @ApiParam(value = "ownerId") @DefaultValue("") @QueryParam("ownerId") String ownerId, @ApiParam(value = "date") @DefaultValue("") @QueryParam("date") String date, @ApiParam(value = "Comma separated list of output file ids") @DefaultValue("") @QueryParam("inputFiles") String inputFiles, @ApiParam(value = "Comma separated list of output file ids") @DefaultValue("") @QueryParam("outputFiles") String outputFiles) { try { long studyId = catalogManager.getStudyId(studyStr, sessionId); return createOkResponse(catalogManager.getAllJobs(studyId, sessionId)); } catch (Exception e) { return createErrorResponse(e); } } @Deprecated @GET @Path("/{study}/variants") @ApiOperation(value = "[DEPRECATED]: use analysis/variant/query instead", position = 10, hidden = true, response = Variant[].class) @ApiImplicitParams({ @ApiImplicitParam(name = "include", value = "Fields included in the response, whole JSON path must be provided", example = "name,attributes", dataType = "string", paramType = "query"), @ApiImplicitParam(name = "exclude", value = "Fields excluded in the response, whole JSON path must be provided", example = "id,status", dataType = "string", paramType = "query"), @ApiImplicitParam(name = "limit", value = "Number of results to be returned in the queries", dataType = "integer", paramType = "query"), @ApiImplicitParam(name = "skip", value = "Number of results to skip in the queries", dataType = "integer", paramType = "query"), // @ApiImplicitParam(name = "count", value = "Total number of results", dataType = "boolean", paramType = "query") }) public Response getVariants(@ApiParam(value = "Study [[user@]project:]study where study and project can be either the id or alias", required = true) @PathParam("study") String studyStr, @ApiParam(value = "List of variant ids") @QueryParam("ids") String ids, @ApiParam(value = "List of regions: {chr}:{start}-{end}") @QueryParam("region") String region, @ApiParam(value = "List of chromosomes") @QueryParam("chromosome") String chromosome, @ApiParam(value = "List of genes") @QueryParam("gene") String gene, @ApiParam(value = "Variant type: [SNV, MNV, INDEL, SV, CNV]") @QueryParam("type") String type, @ApiParam(value = "Reference allele") @QueryParam("reference") String reference, @ApiParam(value = "Main alternate allele") @QueryParam("alternate") String alternate, // @ApiParam(value = "") @QueryParam("studies") String studies, @ApiParam(value = "List of studies to be returned") @QueryParam("returnedStudies") String returnedStudies, @ApiParam(value = "List of samples to be returned") @QueryParam("returnedSamples") String returnedSamples, @ApiParam(value = "List of files to be returned.") @QueryParam("returnedFiles") String returnedFiles, @ApiParam(value = "Variants in specific files") @QueryParam("files") String files, @ApiParam(value = VariantDBAdaptor.FILTER_DESCR) @QueryParam("filter") String filter, @ApiParam(value = "Minor Allele Frequency: [{study:}]{cohort}[<|>|<=|>=]{number}") @QueryParam("maf") String maf, @ApiParam(value = "Minor Genotype Frequency: [{study:}]{cohort}[<|>|<=|>=]{number}") @QueryParam("mgf") String mgf, @ApiParam(value = "Number of missing alleles: [{study:}]{cohort}[<|>|<=|>=]{number}") @QueryParam("missingAlleles") String missingAlleles, @ApiParam(value = "Number of missing genotypes: [{study:}]{cohort}[<|>|<=|>=]{number}") @QueryParam("missingGenotypes") String missingGenotypes, @ApiParam(value = "Specify if the variant annotation must exists.") @QueryParam("annotationExists") boolean annotationExists, @ApiParam(value = "Samples with a specific genotype: " + "{samp_1}:{gt_1}(,{gt_n})*(;{samp_n}:{gt_1}(,{gt_n})*)* e.g. HG0097:0/0;HG0098:0/1,1/1") @QueryParam("genotype") String genotype, @ApiParam(value = VariantDBAdaptor.SAMPLES_DESCR) @QueryParam("samples") String samples, @ApiParam(value = "Consequence type SO term list. e.g. missense_variant,stop_lost or SO:0001583,SO:0001578") @QueryParam("annot-ct") String annot_ct, @ApiParam(value = "XRef") @QueryParam("annot-xref") String annot_xref, @ApiParam(value = "Biotype") @QueryParam("annot-biotype") String annot_biotype, @ApiParam(value = "Polyphen, protein substitution score. " + "[<|>|<=|>=]{number} or [~=|=|]{description} e.g. <=0.9 , =benign") @QueryParam("polyphen") String polyphen, @ApiParam(value = "Sift, protein substitution score. " + "[<|>|<=|>=]{number} or [~=|=|]{description} e.g. >0.1 , ~=tolerant") @QueryParam("sift") String sift, @ApiParam(value = "Protein substitution score. {protein_score}[<|>|<=|>=]{number} or " + "{protein_score}[~=|=]{description} e.g. polyphen>0.1 , sift=tolerant") @QueryParam ("protein_substitution") String protein_substitution, @ApiParam(value = "Conservation score: {conservation_score}[<|>|<=|>=]{number} e.g. " + "phastCons>0.5,phylop<0.1,gerp>0.1") @QueryParam("conservation") String conservation, @ApiParam(value = "Population minor allele frequency: {study}:{population}[<|>|<=|>=]{number}") @QueryParam("annot-population-maf") String annotPopulationMaf, @ApiParam(value = "Alternate Population Frequency: {study}:{population}[<|>|<=|>=]{number}") @QueryParam("alternate_frequency") String alternate_frequency, @ApiParam(value = "Reference Population Frequency: {study}:{population}[<|>|<=|>=]{number}") @QueryParam("reference_frequency") String reference_frequency, @ApiParam(value = "List of transcript annotation flags. e.g. " + "CCDS, basic, cds_end_NF, mRNA_end_NF, cds_start_NF, mRNA_start_NF, seleno") @QueryParam ("annot-transcription-flags") String transcriptionFlags, @ApiParam(value = "List of gene trait association id. e.g. \"umls:C0007222\" , \"OMIM:269600\"") @QueryParam("annot-gene-trait-id") String geneTraitId, @ApiParam(value = "List of gene trait association names. e.g. \"Cardiovascular Diseases\"") @QueryParam("annot-gene-trait-name") String geneTraitName, @ApiParam(value = "List of HPO terms. e.g. \"HP:0000545\"") @QueryParam("annot-hpo") String hpo, @ApiParam(value = "List of GO (Genome Ontology) terms. e.g. \"GO:0002020\"") @QueryParam("annot-go") String go, @ApiParam(value = "List of tissues of interest. e.g. \"tongue\"") @QueryParam("annot-expression") String expression, @ApiParam(value = "List of protein variant annotation keywords") @QueryParam("annot-protein-keywords") String proteinKeyword, @ApiParam(value = "List of drug names") @QueryParam("annot-drug") String drug, @ApiParam(value = "Functional score: " + "{functional_score}[<|>|<=|>=]{number} e.g. cadd_scaled>5.2 , cadd_raw<=0.3") @QueryParam ("annot-functional-score") String functional, @ApiParam(value = "Returned genotype for unknown genotypes. Common values: [0/0, 0|0, ./.]") @QueryParam("unknownGenotype") String unknownGenotype, @ApiParam(value = "Returns the samples metadata group by study. Sample names will appear in the same order as their corresponding genotypes.") @QueryParam("samplesMetadata") boolean samplesMetadata, @ApiParam(value = "Count results", required = false) @QueryParam("count") boolean count, @ApiParam(value = "Sort the results", required = false) @QueryParam("sort") boolean sort, @ApiParam(value = "Group variants by: [ct, gene, ensemblGene]", required = false) @DefaultValue("") @QueryParam("groupBy") String groupBy, @ApiParam(value = "Calculate histogram. Requires one region.", required = false) @DefaultValue("false") @QueryParam("histogram") boolean histogram, @ApiParam(value = "Histogram interval size", required = false) @DefaultValue("2000") @QueryParam("interval") int interval, @ApiParam(value = "Merge results", required = false) @DefaultValue("false") @QueryParam("merge") boolean merge) { try { List<Long> studyIds = catalogManager.getStudyIds(studyStr, sessionId); List<QueryResult> queryResults = new LinkedList<>(); for (Long studyId : studyIds) { QueryResult queryResult; // Get all query options QueryOptions queryOptions = new QueryOptions(uriInfo.getQueryParameters(), true); Query query = VariantStorageManager.getVariantQuery(queryOptions); query.putIfAbsent(VariantDBAdaptor.VariantQueryParams.STUDIES.key(), studyId); if (count) { queryResult = variantManager.count(query, sessionId); } else if (histogram) { queryResult = variantManager.getFrequency(query, interval, sessionId); } else if (StringUtils.isNotEmpty(groupBy)) { queryResult = variantManager.groupBy(groupBy, query, queryOptions, sessionId); } else { queryResult = variantManager.get(query, queryOptions, sessionId); } queryResults.add(queryResult); } return createOkResponse(queryResults); } catch (Exception e) { return createErrorResponse(e); } } @Deprecated @GET @Path("/{study}/alignments") @ApiOperation(value = "[DEPCRATED]: use analysis/alignment/query instead", position = 11, hidden = true, response = Alignment[].class) @ApiImplicitParams({ @ApiImplicitParam(name = "include", value = "Fields included in the response, whole JSON path must be provided", example = "name,attributes", dataType = "string", paramType = "query"), @ApiImplicitParam(name = "exclude", value = "Fields excluded in the response, whole JSON path must be provided", example = "id,status", dataType = "string", paramType = "query"), @ApiImplicitParam(name = "limit", value = "Number of results to be returned in the queries", dataType = "integer", paramType = "query"), @ApiImplicitParam(name = "skip", value = "Number of results to skip in the queries", dataType = "integer", paramType = "query"), @ApiImplicitParam(name = "count", value = "Total number of results", dataType = "boolean", paramType = "query") }) public Response getAlignments(@ApiParam(value = "Study [[user@]project:]study where study and project can be either the id or alias", required = true) @PathParam("study") String studyStr, @ApiParam(value = "sample id", required = false) @DefaultValue("") @QueryParam("sampleId") String sampleIds, @ApiParam(value = "file id", required = false) @DefaultValue("") @QueryParam("fileId") String fileIds, @ApiParam(value = "region with a maximum value of 10000 nucleotides", required = true) @DefaultValue("") @QueryParam("region") String region, @ApiParam(value = "view_as_pairs", required = false) @DefaultValue("false") @QueryParam("view_as_pairs") boolean view_as_pairs, @ApiParam(value = "include_coverage", required = false) @DefaultValue("true") @QueryParam("include_coverage") boolean include_coverage, @ApiParam(value = "process_differences", required = false) @DefaultValue("true") @QueryParam("process_differences") boolean process_differences, @ApiParam(value = "histogram", required = false) @DefaultValue("false") @QueryParam("histogram") boolean histogram, @ApiParam(value = "interval", required = false) @DefaultValue("2000") @QueryParam("interval") int interval) { query.put(VariantDBAdaptor.VariantQueryParams.STUDIES.key(), studyStr); List<Region> regions = Region.parseRegions(region); List<QueryResult> results = new ArrayList<>(); // QueryResult alignmentsByRegion; QueryResult alignmentsByRegion; // TODO if SampleIds are passed we need to get the BAM files for them and execute the code below long studyId = 4; long sampleId = 33; QueryOptions qOptions = new QueryOptions(queryOptions); try { File file = catalogManager.getAllFiles(studyId, query .append(FileDBAdaptor.QueryParams.BIOFORMAT.key(), File.Bioformat.ALIGNMENT) .append(FileDBAdaptor.QueryParams.SAMPLE_IDS.key(), sampleId) .append(FileDBAdaptor.QueryParams.INDEX_STATUS_NAME.key(), FileIndex.IndexStatus.READY), qOptions, sessionId).first(); } catch (CatalogException e) { e.printStackTrace(); } for (String fileId : fileIds.split(",")) { long fileIdNum; File file; URI fileUri; try { AbstractManager.MyResourceId resource = catalogManager.getFileManager().getId(fileId, Long.toString(studyId), sessionId); fileIdNum = resource.getResourceId(); QueryResult<File> queryResult = catalogManager.getFile(fileIdNum, sessionId); file = queryResult.getResult().get(0); fileUri = catalogManager.getFileUri(file); } catch (CatalogException e) { e.printStackTrace(); return createErrorResponse(e); } // if (!file.getType().equals(File.Type.INDEX)) { if (file.getIndex() == null || !file.getIndex().getStatus().getName().equals(FileIndex.IndexStatus.READY)) { return createErrorResponse("", "File {id:" + file.getId() + " name:'" + file.getName() + "'} " + " is not an indexed file."); } ObjectMap indexAttributes = new ObjectMap(file.getIndex().getAttributes()); DataStore dataStore; try { dataStore = StorageOperation.getDataStore(catalogManager, Integer.parseInt(studyStr), File.Bioformat.VARIANT, sessionId); } catch (CatalogException e) { e.printStackTrace(); return createErrorResponse(e); } String storageEngine = dataStore.getStorageEngine(); String dbName = dataStore.getDbName(); int chunkSize = indexAttributes.getInt("coverageChunkSize", 200); QueryOptions queryOptions = new QueryOptions(); queryOptions.put(AlignmentDBAdaptor.QO_FILE_ID, Long.toString(fileIdNum)); queryOptions.put(AlignmentDBAdaptor.QO_BAM_PATH, fileUri.getPath()); //TODO: Make uri-compatible queryOptions.put(AlignmentDBAdaptor.QO_VIEW_AS_PAIRS, view_as_pairs); queryOptions.put(AlignmentDBAdaptor.QO_INCLUDE_COVERAGE, include_coverage); queryOptions.put(AlignmentDBAdaptor.QO_PROCESS_DIFFERENCES, process_differences); queryOptions.put(AlignmentDBAdaptor.QO_INTERVAL_SIZE, interval); queryOptions.put(AlignmentDBAdaptor.QO_HISTOGRAM, histogram); queryOptions.put(AlignmentDBAdaptor.QO_COVERAGE_CHUNK_SIZE, chunkSize); if (indexAttributes.containsKey("baiFileId")) { File baiFile = null; try { baiFile = catalogManager.getFile(indexAttributes.getInt("baiFileId"), sessionId).getResult().get(0); URI baiUri = catalogManager.getFileUri(baiFile); queryOptions.put(AlignmentDBAdaptor.QO_BAI_PATH, baiUri.getPath()); //TODO: Make uri-compatible } catch (CatalogException e) { e.printStackTrace(); logger.error("Can't obtain bai file for file " + fileIdNum, e); } } AlignmentDBAdaptor dbAdaptor; try { AlignmentStorageEngine alignmentStorageManager = storageEngineFactory.getAlignmentStorageEngine(storageEngine); dbAdaptor = alignmentStorageManager.getDBAdaptor(dbName); } catch (ClassNotFoundException | IllegalAccessException | InstantiationException | StorageEngineException e) { return createErrorResponse(e); } if (histogram) { if (regions.size() != 1) { return createErrorResponse("", "Histogram fetch only accepts one region."); } alignmentsByRegion = dbAdaptor.getAllIntervalFrequencies(regions.get(0), new QueryOptions(queryOptions)); } else { alignmentsByRegion = dbAdaptor.getAllAlignmentsByRegion(regions, new QueryOptions(queryOptions)); } results.add(alignmentsByRegion); } return createOkResponse(results); } @GET @Path("/{study}/scanFiles") @ApiOperation(value = "Scan the study folder to find untracked or missing files", position = 12) public Response scanFiles(@ApiParam(value = "Study [[user@]project:]study where study and project can be either the id or alias", required = true) @PathParam("study") String studyStr) { try { long studyId = catalogManager.getStudyId(studyStr, sessionId); Study study = catalogManager.getStudy(studyId, sessionId).first(); FileScanner fileScanner = new FileScanner(catalogManager); /** First, run CheckStudyFiles to find new missing files **/ List<File> checkStudyFiles = fileScanner.checkStudyFiles(study, false, sessionId); List<File> found = checkStudyFiles .stream() .filter(f -> f.getStatus().getName().equals(File.FileStatus.READY)) .collect(Collectors.toList()); /** Get untracked files **/ Map<String, URI> untrackedFiles = fileScanner.untrackedFiles(study, sessionId); /** Get missing files **/ List<File> missingFiles = catalogManager.getAllFiles(studyId, query.append(FileDBAdaptor.QueryParams.STATUS_NAME.key(), File.FileStatus.MISSING), queryOptions, sessionId).getResult(); ObjectMap fileStatus = new ObjectMap("untracked", untrackedFiles).append("found", found).append("missing", missingFiles); return createOkResponse(new QueryResult<>("status", 0, 1, 1, null, null, Collections.singletonList(fileStatus))); // /** Print pretty **/ // int maxFound = found.stream().map(f -> f.getPath().length()).max(Comparator.<Integer>naturalOrder()).orElse(0); // int maxUntracked = untrackedFiles.keySet().stream().map(String::length).max(Comparator.<Integer>naturalOrder()).orElse(0); // int maxMissing = missingFiles.stream().map(f -> f.getPath().length()).max(Comparator.<Integer>naturalOrder()).orElse(0); // // String format = "\t%-" + Math.max(Math.max(maxMissing, maxUntracked), maxFound) + "s -> %s\n"; // // if (!untrackedFiles.isEmpty()) { // System.out.println("UNTRACKED files"); // untrackedFiles.forEach((s, u) -> System.out.printf(format, s, u)); // System.out.println("\n"); // } // // if (!missingFiles.isEmpty()) { // System.out.println("MISSING files"); // for (File file : missingFiles) { // System.out.printf(format, file.getPath(), catalogManager.getFileUri(file)); // } // System.out.println("\n"); // } // // if (!found.isEmpty()) { // System.out.println("FOUND files"); // for (File file : found) { // System.out.printf(format, file.getPath(), catalogManager.getFileUri(file)); // } // } } catch (Exception e) { return createErrorResponse(e); } } @GET @Path("/{study}/resyncFiles") @ApiOperation(value = "Scan the study folder to find untracked or missing files.", notes = "This method is intended to keep the " + "consistency between the database and the file system. It will check all the files and folders belonging to the study and " + "will keep track of those new files and/or folders found in the file system as well as update the status of those " + "files/folders that are no longer available in the file system setting their status to MISSING.") public Response resyncFiles(@ApiParam(value = "Study [[user@]project:]study where study and project can be either the id or alias", required = true) @PathParam("study") String studyStr) { try { long studyId = catalogManager.getStudyId(studyStr, sessionId); Study study = catalogManager.getStudy(studyId, sessionId).first(); FileScanner fileScanner = new FileScanner(catalogManager); /* Resync files */ List<File> resyncFiles = fileScanner.reSync(study, false, sessionId); return createOkResponse(new QueryResult<>("status", 0, 1, 1, null, null, Arrays.asList(resyncFiles))); } catch (Exception e) { return createErrorResponse(e); } } @GET @Path("/{study}/groups") @ApiOperation(value = "Return the groups present in the studies", position = 13, response = Group[].class) public Response getGroups(@ApiParam(value = "Study [[user@]project:]study where study and project can be either the id or alias", required = true) @PathParam("study") String studyStr) { try { QueryResult<Group> allGroups = catalogManager.getAllGroups(studyStr, sessionId); return createOkResponse(allGroups); } catch (Exception e) { return createErrorResponse(e); } } @GET @Path("/{study}/groups/create") @ApiOperation(value = "Create a group", position = 14, hidden = true) public Response createGroup(@ApiParam(value = "Study [[user@]project:]study where study and project can be either the id or alias", required = true) @PathParam("study") String studyStr, @ApiParam(value = "Id of the new group to be created", required = true) @QueryParam("groupId") String groupId, @ApiParam(value = "Comma separated list of users to take part of the group", required = true) @DefaultValue("") @QueryParam("users") String users) { try { QueryResult group = catalogManager.createGroup(studyStr, groupId, users, sessionId); return createOkResponse(group); } catch (Exception e) { return createErrorResponse(e); } } @POST @Path("/{study}/groups/create") @ApiOperation(value = "Create a group", position = 14) public Response createGroupPOST(@ApiParam(value = "Study [[user@]project:]study where study and project can be either the id or alias", required = true) @PathParam("study") String studyStr, @ApiParam(value="JSON containing 'groupId' as a mandatory parameter and optionally 'users' containing" + " the list of users to take part of the group", required = true) ObjectMap params) { if (StringUtils.isEmpty(params.getString("groupId"))) { return createErrorResponse(new CatalogException("groupId key missing.")); } try { QueryResult group = catalogManager.createGroup(studyStr, params.getString("groupId"), params.getString("users"), sessionId); return createOkResponse(group); } catch (Exception e) { return createErrorResponse(e); } } @GET @Path("/{study}/groups/{groupId}/info") @ApiOperation(value = "Return the group", position = 15) public Response getGroup(@ApiParam(value = "Study [[user@]project:]study where study and project can be either the id or alias", required = true) @PathParam("study") String studyStr, @ApiParam(value = "groupId", required = true) @DefaultValue("") @PathParam("groupId") String groupId) { try { QueryResult<Group> group = catalogManager.getGroup(studyStr, groupId, sessionId); return createOkResponse(group); } catch (Exception e) { return createErrorResponse(e); } } @GET @Path("/{study}/groups/{groupId}/update") @ApiOperation(value = "Updates the members of the group", hidden = true) public Response addMembersToGroup(@ApiParam(value = "Study [[user@]project:]study where study and project can be either the id or " + "alias", required = true) @PathParam("study") String studyStr, @ApiParam(value = "groupId", required = true) @DefaultValue("") @PathParam("groupId") String groupId, @ApiParam(value = "Comma separated list of users that will be added to the group") @QueryParam("addUsers") String addUsers, @ApiParam(value = "Comma separated list of users that will be part of the group. Previous users " + "will be removed.", required = false) @QueryParam("setUsers") String setUsers, @ApiParam(value = "Comma separated list of users that will be removed from the group") @QueryParam("removeUsers") String removeUsers) { try { return createOkResponse(catalogManager.updateGroup(studyStr, groupId, addUsers, removeUsers, setUsers, sessionId)); } catch (Exception e) { return createErrorResponse(e); } } @POST @Path("/{study}/groups/{groupId}/update") @ApiOperation(value = "Updates the members of the group") public Response addMembersToGroupPOST( @ApiParam(value = "Study [[user@]project:]study where study and project can be either the id or " + "alias", required = true) @PathParam("study") String studyStr, @ApiParam(value = "groupId", required = true) @DefaultValue("") @PathParam("groupId") String groupId, @ApiParam(value="JSON containing one of the keys 'addUsers', 'setUsers' or 'removeUsers'", required = true) ObjectMap params) { try { return createOkResponse(catalogManager. updateGroup(studyStr, groupId, params.getString("addUsers"), params.getString("removeUsers"), params.getString("setUsers"), sessionId)); } catch (Exception e) { return createErrorResponse(e); } } @GET @Path("/{study}/groups/{groupId}/delete") @ApiOperation(value = "Delete the group", position = 17, notes = "Delete the group selected from the study.") public Response deleteMembersFromGroup(@ApiParam(value = "Study [[user@]project:]study where study and project can be either the id " + "or alias", required = true) @PathParam("study") String studyStr, @ApiParam(value = "groupId", required = true) @DefaultValue("") @PathParam("groupId") String groupId) { try { return createOkResponse(catalogManager.deleteGroup(studyStr, groupId, sessionId)); } catch (Exception e) { return createErrorResponse(e); } } @GET @Path("/{study}/acl") @ApiOperation(value = "Return the acl of the study", position = 18) public Response getAcls(@ApiParam(value = "Study [[user@]project:]study where study and project can be either the id or alias", required = true) @PathParam("study") String studyStr) { try { return createOkResponse(catalogManager.getAllStudyAcls(studyStr, sessionId)); } catch (Exception e) { return createErrorResponse(e); } } public static class CreateAclCommands { public String permissions; public String members; } public static class CreateAclCommandsTemplate extends CreateAclCommands { public String templateId; } @GET @Path("/{study}/acl/create") @ApiOperation(value = "Define a set of permissions for a list of users or groups", hidden = true) public Response createRole(@ApiParam(value = "Study [[user@]project:]study where study and project can be either the id or alias", required = true) @PathParam("study") String studyStr, @ApiParam(value = "Comma separated list of members. Accepts: '{userId}', '@{groupId}' or '*'", required = true) @QueryParam("members") String members, @ApiParam(value = "Comma separated list of permissions that will be granted to the member list") @DefaultValue("") @QueryParam("permissions") String permissions, @ApiParam(value = "Template of permissions to be used (admin, analyst or view_only)") @QueryParam("templateId") String templateId) { try { return createOkResponse(catalogManager.createStudyAcls(studyStr, members, permissions, templateId, sessionId)); } catch (Exception e) { return createErrorResponse(e); } } @POST @Path("/{study}/acl/create") @ApiOperation(value = "Define a set of permissions for a list of users or groups") public Response createRolePOST( @ApiParam(value = "Study [[user@]project:]study where study and project can be either the id or alias", required = true) @PathParam("study") String studyStr, @ApiParam(value="JSON containing the parameters defined in GET. Mandatory keys: 'members'", required = true) CreateAclCommandsTemplate params) { if (params == null || StringUtils.isEmpty(params.members)) { return createErrorResponse(new CatalogException("members parameter not found")); } try { return createOkResponse(catalogManager.createStudyAcls(studyStr, params.members, params.permissions, params.templateId, sessionId)); } catch (Exception e) { return createErrorResponse(e); } } @GET @Path("/{study}/acl/{memberId}/info") @ApiOperation(value = "Return the set of permissions granted for the user or group", position = 20) public Response getAcl(@ApiParam(value = "Study [[user@]project:]study where study and project can be either the id or alias", required = true) @PathParam("study") String studyStr, @ApiParam(value = "User or group id", required = true) @PathParam("memberId") String memberId) { try { return createOkResponse(catalogManager.getStudyAcl(studyStr, memberId, sessionId)); } catch (Exception e) { return createErrorResponse(e); } } @GET @Path("/{study}/acl/{memberId}/update") @ApiOperation(value = "Update the set of permissions granted for the user or group", hidden = true, position = 21) public Response updateAcl(@ApiParam(value = "Study [[user@]project:]study where study and project can be either the id or alias", required = true) @PathParam("study") String studyStr, @ApiParam(value = "User or group id", required = true) @PathParam("memberId") String memberId, @ApiParam(value = "Comma separated list of permissions to add") @QueryParam("add") String addPermissions, @ApiParam(value = "Comma separated list of permissions to remove") @QueryParam("remove") String removePermissions, @ApiParam(value = "Comma separated list of permissions to set") @QueryParam("set") String setPermissions) { try { return createOkResponse(catalogManager.updateStudyAcl(studyStr, memberId, addPermissions, removePermissions, setPermissions, sessionId)); } catch (Exception e) { return createErrorResponse(e); } } public static class MemberAclUpdate { public String add; public String set; public String remove; } @POST @Path("/{study}/acl/{memberId}/update") @ApiOperation(value = "Update the set of permissions granted for the user or group", position = 21) public Response updateAcl( @ApiParam(value = "Study [[user@]project:]study where study and project can be either the id or alias", required = true) @PathParam("study") String studyStr, @ApiParam(value = "User or group id", required = true) @PathParam("memberId") String memberId, @ApiParam(value="JSON containing one of the keys 'add', 'set' or 'remove'", required = true) MemberAclUpdate params) { // if (params == null || params.isEmpty()) { // return createErrorResponse(new CatalogException("At least one of the keys 'addUsers', 'setUsers' or 'removeUsers'")); // } try { return createOkResponse(catalogManager.updateStudyAcl(studyStr, memberId, params.add, params.remove, params.set, sessionId)); } catch (Exception e) { return createErrorResponse(e); } } @GET @Path("/{study}/acl/{memberId}/delete") @ApiOperation(value = "Delete all the permissions granted for the user or group", position = 22) public Response deleteAcl(@ApiParam(value = "Study [[user@]project:]study where study and project can be either the id or alias", required = true) @PathParam("study") String studyStr, @ApiParam(value = "User or group id", required = true) @PathParam("memberId") String memberId) { try { return createOkResponse(catalogManager.removeStudyAcl(studyStr, memberId, sessionId)); } catch (Exception e) { return createErrorResponse(e); } } }