package org.opencb.opencga.app.cli.main.executors.analysis;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import ga4gh.Reads;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import org.ga4gh.models.ReadAlignment;
import org.opencb.biodata.models.alignment.RegionCoverage;
import org.opencb.biodata.tools.alignment.converters.SAMRecordToAvroReadAlignmentConverter;
import org.opencb.biodata.tools.alignment.stats.AlignmentGlobalStats;
import org.opencb.commons.datastore.core.ObjectMap;
import org.opencb.commons.datastore.core.QueryResponse;
import org.opencb.opencga.app.cli.analysis.options.AlignmentCommandOptions;
import org.opencb.opencga.app.cli.main.executors.OpencgaCommandExecutor;
import org.opencb.opencga.catalog.exceptions.CatalogException;
import org.opencb.opencga.client.rest.OpenCGAClient;
import org.opencb.opencga.server.grpc.AlignmentServiceGrpc;
import org.opencb.opencga.server.grpc.GenericAlignmentServiceModel;
import org.opencb.opencga.server.grpc.ServiceTypesModel;
import org.opencb.opencga.storage.core.alignment.AlignmentDBAdaptor;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* Created by pfurio on 11/11/16.
*/
public class AlignmentCommandExecutor extends OpencgaCommandExecutor {
private AlignmentCommandOptions alignmentCommandOptions;
public AlignmentCommandExecutor(AlignmentCommandOptions alignmentCommandOptions) {
super(alignmentCommandOptions.analysisCommonOptions);
this.alignmentCommandOptions = alignmentCommandOptions;
}
@Override
public void execute() throws Exception {
logger.debug("Executing alignment command line");
String subCommandString = getParsedSubCommand(alignmentCommandOptions.jCommander);
QueryResponse queryResponse = null;
switch (subCommandString) {
case "index":
queryResponse = index();
break;
case "query":
query();
break;
case "stats":
queryResponse = stats();
break;
case "coverage":
queryResponse = coverage();
break;
default:
logger.error("Subcommand not valid");
break;
}
createOutput(queryResponse);
}
private QueryResponse index() throws CatalogException, IOException {
logger.debug("Indexing alignment(s)");
String fileIds = alignmentCommandOptions.indexAlignmentCommandOptions.fileId;
ObjectMap o = new ObjectMap();
o.putIfNotNull("study", alignmentCommandOptions.indexAlignmentCommandOptions.study);
o.putIfNotNull("outDir", alignmentCommandOptions.indexAlignmentCommandOptions.outdirId);
return openCGAClient.getAlignmentClient().index(fileIds, o);
}
private void query() throws CatalogException, IOException, InterruptedException {
logger.debug("Querying alignment(s)");
String rpc = alignmentCommandOptions.queryAlignmentCommandOptions.rpc;
if (rpc == null) {
rpc = "auto";
}
QueryResponse<ReadAlignment> queryResponse = null;
if (rpc.toLowerCase().equals("rest")) {
queryResponse = queryRest(alignmentCommandOptions.queryAlignmentCommandOptions);
} else if (rpc.toLowerCase().equals("grpc")) {
queryGRPC(alignmentCommandOptions.queryAlignmentCommandOptions);
} else {
try {
queryGRPC(alignmentCommandOptions.queryAlignmentCommandOptions);
} catch(Exception e) {
System.out.println("GRPC not available. Trying on REST.");
queryResponse = queryRest(alignmentCommandOptions.queryAlignmentCommandOptions);
}
}
// It will only enter this if when the query has been done via REST
if (queryResponse != null) {
if (alignmentCommandOptions.queryAlignmentCommandOptions.commonOptions.outputFormat.toLowerCase().contains("text")) {
SAMRecordToAvroReadAlignmentConverter converter = new SAMRecordToAvroReadAlignmentConverter();
for (ReadAlignment readAlignment : queryResponse.allResults()) {
System.out.print(converter.from(readAlignment).getSAMString());
}
} else {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
objectMapper.configure(MapperFeature.REQUIRE_SETTERS_FOR_GETTERS, true);
ObjectWriter objectWriter = objectMapper.writerWithDefaultPrettyPrinter();
try {
System.out.println(objectWriter.writeValueAsString(queryResponse.getResponse()));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private QueryResponse<ReadAlignment> queryRest(AlignmentCommandOptions.QueryAlignmentCommandOptions commandOptions)
throws CatalogException, IOException {
String study = resolveStudy(alignmentCommandOptions.queryAlignmentCommandOptions.study);
String fileIds = commandOptions.fileId;
ObjectMap o = new ObjectMap();
o.putIfNotNull("study", study);
o.putIfNotNull(AlignmentDBAdaptor.QueryParams.REGION.key(), commandOptions.region);
o.putIfNotNull(AlignmentDBAdaptor.QueryParams.MIN_MAPQ.key(), commandOptions.minMappingQuality);
o.putIfNotNull("limit", commandOptions.limit);
QueryResponse<ReadAlignment> query = openCGAClient.getAlignmentClient().query(fileIds, o);
return query;
}
private void queryGRPC(AlignmentCommandOptions.QueryAlignmentCommandOptions commandOptions) throws InterruptedException {
// StopWatch watch = new StopWatch();
// watch.start();
// We create the OpenCGA gRPC request object with the query, queryOptions, storageEngine and database
String study = resolveStudy(alignmentCommandOptions.queryAlignmentCommandOptions.study);
Map<String, String> query = new HashMap<>();
addParam(query, "fileId", commandOptions.fileId);
addParam(query, "sid", commandOptions.commonOptions.sessionId);
addParam(query, "study", study);
addParam(query, AlignmentDBAdaptor.QueryParams.REGION.key(), commandOptions.region);
addParam(query, AlignmentDBAdaptor.QueryParams.MIN_MAPQ.key(), commandOptions.minMappingQuality);
Map<String, String> queryOptions = new HashMap<>();
addParam(queryOptions, AlignmentDBAdaptor.QueryParams.CONTAINED.key(), commandOptions.contained);
addParam(queryOptions, AlignmentDBAdaptor.QueryParams.MD_FIELD.key(), commandOptions.mdField);
addParam(queryOptions, AlignmentDBAdaptor.QueryParams.BIN_QUALITIES.key(),commandOptions.binQualities);
addParam(queryOptions, AlignmentDBAdaptor.QueryParams.LIMIT.key(), commandOptions.limit);
addParam(queryOptions, AlignmentDBAdaptor.QueryParams.SKIP.key(), commandOptions.skip);
GenericAlignmentServiceModel.Request request = GenericAlignmentServiceModel.Request.newBuilder()
.putAllQuery(query)
.putAllOptions(queryOptions)
.build();
// Connecting to the server host and port
String[] split = clientConfiguration.getGrpc().getHost().split(":");
String grpcServerHost = split[0];
int grpcServerPort = 9091;
if (split.length == 2) {
grpcServerPort = Integer.parseInt(split[1]);
}
logger.debug("Connecting to gRPC server at {}:{}", grpcServerHost, grpcServerPort);
// We create the gRPC channel to the specified server host and port
ManagedChannel channel = ManagedChannelBuilder.forAddress(grpcServerHost, grpcServerPort)
.usePlaintext(true)
.build();
// We use a blocking stub to execute the query to gRPC
AlignmentServiceGrpc.AlignmentServiceBlockingStub serviceBlockingStub = AlignmentServiceGrpc.newBlockingStub(channel);
if (commandOptions.count) {
ServiceTypesModel.LongResponse count = serviceBlockingStub.count(request);
String pretty = "";
if (commandOptions.commonOptions.outputFormat.toLowerCase().equals("extended_text")) {
pretty = "\nThe number of alignments is ";
}
System.out.println(pretty + count.getValue() + "\n");
} else {
if (commandOptions.commonOptions.outputFormat.toLowerCase().contains("text")) {
// Output in SAM format
Iterator<ServiceTypesModel.StringResponse> alignmentIterator = serviceBlockingStub.getAsSam(request);
// watch.stop();
// System.out.println("Time: " + watch.getTime());
int limit = commandOptions.limit;
if (limit > 0) {
long cont = 0;
while (alignmentIterator.hasNext() && cont < limit) {
ServiceTypesModel.StringResponse next = alignmentIterator.next();
cont++;
System.out.print(next.getValue());
}
} else {
while (alignmentIterator.hasNext()) {
ServiceTypesModel.StringResponse next = alignmentIterator.next();
System.out.print(next.getValue());
}
}
} else {
// Output in json format
Iterator<Reads.ReadAlignment> alignmentIterator = serviceBlockingStub.get(request);
// watch.stop();
// System.out.println("Time: " + watch.getTime());
int limit = commandOptions.limit;
if (limit > 0) {
long cont = 0;
while (alignmentIterator.hasNext() && cont < limit) {
Reads.ReadAlignment next = alignmentIterator.next();
cont++;
System.out.println(next.toString());
}
} else {
while (alignmentIterator.hasNext()) {
Reads.ReadAlignment next = alignmentIterator.next();
System.out.println(next.toString());
}
}
}
}
channel.shutdown().awaitTermination(1, TimeUnit.SECONDS);
}
private QueryResponse stats() throws CatalogException, IOException {
ObjectMap objectMap = new ObjectMap();
// objectMap.putIfNotNull("fileId", alignmentCommandOptions.statsAlignmentCommandOptions.fileId);
objectMap.putIfNotNull("sid", alignmentCommandOptions.statsAlignmentCommandOptions.commonOptions.sessionId);
objectMap.putIfNotNull("study", alignmentCommandOptions.statsAlignmentCommandOptions.study);
objectMap.putIfNotNull("region", alignmentCommandOptions.statsAlignmentCommandOptions.region);
objectMap.putIfNotNull("minMapQ", alignmentCommandOptions.statsAlignmentCommandOptions.minMappingQuality);
if (alignmentCommandOptions.statsAlignmentCommandOptions.contained) {
objectMap.put("contained", alignmentCommandOptions.statsAlignmentCommandOptions.contained);
}
OpenCGAClient openCGAClient = new OpenCGAClient(clientConfiguration);
QueryResponse<AlignmentGlobalStats> globalStats = openCGAClient.getAlignmentClient()
.stats(alignmentCommandOptions.statsAlignmentCommandOptions.fileId, objectMap);
return globalStats;
// for (AlignmentGlobalStats alignmentGlobalStats : globalStats.allResults()) {
// System.out.println(alignmentGlobalStats.toJSON());
// }
}
private QueryResponse coverage() throws CatalogException, IOException {
ObjectMap objectMap = new ObjectMap();
// objectMap.putIfNotNull("fileId", alignmentCommandOptions.coverageAlignmentCommandOptions.fileId);
objectMap.putIfNotNull("sid", alignmentCommandOptions.coverageAlignmentCommandOptions.commonOptions.sessionId);
objectMap.putIfNotNull("study", alignmentCommandOptions.coverageAlignmentCommandOptions.study);
objectMap.putIfNotNull("region", alignmentCommandOptions.coverageAlignmentCommandOptions.region);
objectMap.putIfNotNull("minMapQ", alignmentCommandOptions.coverageAlignmentCommandOptions.minMappingQuality);
if (alignmentCommandOptions.coverageAlignmentCommandOptions.contained) {
objectMap.put("contained", alignmentCommandOptions.coverageAlignmentCommandOptions.contained);
}
OpenCGAClient openCGAClient = new OpenCGAClient(clientConfiguration);
QueryResponse<RegionCoverage> globalStats = openCGAClient.getAlignmentClient()
.coverage(alignmentCommandOptions.coverageAlignmentCommandOptions.fileId, objectMap);
return globalStats;
// for (RegionCoverage regionCoverage : globalStats.allResults()) {
// System.out.println(regionCoverage.toString());
// }
}
private void addParam(Map<String, String> map, String key, Object value) {
if (value == null) {
return;
}
if (value instanceof String) {
if (!((String) value).isEmpty()) {
map.put(key, (String) value);
}
} else if (value instanceof Integer) {
map.put(key, Integer.toString((int) value));
} else if (value instanceof Boolean) {
map.put(key, Boolean.toString((boolean) value));
} else {
throw new UnsupportedOperationException();
}
}
}