package org.opencb.opencga.storage.core.manager;
import ga4gh.Reads;
import org.apache.commons.lang3.time.StopWatch;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.ObjectReader;
import org.codehaus.jackson.map.ObjectWriter;
import org.ga4gh.models.ReadAlignment;
import org.opencb.biodata.models.alignment.RegionCoverage;
import org.opencb.biodata.tools.alignment.stats.AlignmentGlobalStats;
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.commons.utils.FileUtils;
import org.opencb.opencga.catalog.db.api.FileDBAdaptor;
import org.opencb.opencga.catalog.exceptions.CatalogException;
import org.opencb.opencga.catalog.managers.CatalogManager;
import org.opencb.opencga.catalog.models.File;
import org.opencb.opencga.catalog.models.Study;
import org.opencb.opencga.catalog.utils.ParamUtils;
import org.opencb.opencga.storage.core.StorageEngineFactory;
import org.opencb.opencga.storage.core.alignment.AlignmentStorageEngine;
import org.opencb.opencga.storage.core.alignment.iterators.AlignmentIterator;
import org.opencb.opencga.storage.core.alignment.local.LocalAlignmentStorageEngine;
import org.opencb.opencga.storage.core.exceptions.StorageEngineException;
import org.opencb.opencga.storage.core.manager.models.FileInfo;
import org.opencb.opencga.storage.core.manager.models.StudyInfo;
import java.io.IOException;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
/**
* Created by pfurio on 31/10/16.
*/
public class AlignmentStorageManager extends StorageManager {
private AlignmentStorageEngine alignmentStorageManager;
private static final String GLOBAL_STATS = "globalStats";
public AlignmentStorageManager(CatalogManager catalogManager, StorageEngineFactory storageEngineFactory) {
super(catalogManager, storageEngineFactory);
// TODO: Create this alignmentStorageManager by reflection
this.alignmentStorageManager = new LocalAlignmentStorageEngine();
}
public void index(String studyIdStr, String fileIdStr, ObjectMap options, String sessionId) throws Exception {
options = ParamUtils.defaultObject(options, ObjectMap::new);
StopWatch watch = new StopWatch();
StudyInfo studyInfo = getStudyInfo(studyIdStr, fileIdStr, sessionId);
checkAlignmentBioformat(studyInfo.getFileInfos());
FileInfo fileInfo = studyInfo.getFileInfo();
// ObjectMap fileAndStudyId = getFileAndStudyId(studyIdStr, fileIdStr, sessionId);
// long studyId = fileAndStudyId.getLong("studyId");
// long fileId = fileAndStudyId.getLong("fileId");
// Path filePath = getFilePath(fileId, sessionId);
// Path workspace = getWorkspace(studyId, sessionId);
List<URI> fileUris = Arrays.asList(fileInfo.getPath().toUri());
// TODO: Check if index is already created and link bai file
logger.info("Creating index...");
watch.start();
alignmentStorageManager
.index(fileUris, studyInfo.getWorkspace().toUri(), false, options.getBoolean("transform"), options.getBoolean("load"));
watch.stop();
logger.info("Indexing took {} seconds", watch.getTime() / 1000.0);
// Create the stats and store them in catalog
logger.info("Calculating the stats...");
watch.reset();
watch.start();
QueryResult<AlignmentGlobalStats> stats = alignmentStorageManager.getDBAdaptor()
.stats(fileInfo.getPath(), studyInfo.getWorkspace());
if (stats != null && stats.getNumResults() == 1) {
// Store the stats in catalog
ObjectWriter objectWriter = new ObjectMapper().typedWriter(AlignmentGlobalStats.class);
ObjectMap globalStats = new ObjectMap(GLOBAL_STATS, objectWriter.writeValueAsString(stats.first()));
ObjectMap alignmentStats = new ObjectMap(FileDBAdaptor.QueryParams.STATS.key(), globalStats);
catalogManager.getFileManager().update(fileInfo.getFileId(), alignmentStats, new QueryOptions(), sessionId);
// Remove the stats file
Path statsFile = studyInfo.getWorkspace().resolve(fileInfo.getPath().toFile().getName() + ".stats");
if (statsFile.toFile().exists()) {
Files.delete(statsFile);
}
}
watch.stop();
logger.info("Stats calculation took {} seconds", watch.getTime() / 1000.0);
// Create the coverage
logger.info("Calculating the coverage...");
watch.reset();
watch.start();
alignmentStorageManager.getDBAdaptor().coverage(fileInfo.getPath(), studyInfo.getWorkspace());
watch.stop();
logger.info("Coverage calculation took {} seconds", watch.getTime() / 1000.0);
}
public QueryResult<ReadAlignment> query(String studyIdStr, String fileIdStr, Query query, QueryOptions options, String sessionId)
throws CatalogException, IOException, StorageEngineException {
query = ParamUtils.defaultObject(query, Query::new);
options = ParamUtils.defaultObject(options, QueryOptions::new);
StudyInfo studyInfo = getStudyInfo(studyIdStr, fileIdStr, sessionId);
checkAlignmentBioformat(studyInfo.getFileInfos());
// ObjectMap fileAndStudyId = getFileAndStudyId(studyIdStr, fileIdStr, sessionId);
// long fileId = fileAndStudyId.getLong("fileId");
// Path filePath = getFilePath(fileId, sessionId);
return alignmentStorageManager.getDBAdaptor().get(studyInfo.getFileInfo().getPath(), query, options);
}
public AlignmentIterator<Reads.ReadAlignment> iterator(String studyId, String fileId, Query query, QueryOptions options,
String sessionId) throws CatalogException, IOException, StorageEngineException {
return iterator(studyId, fileId, query, options, sessionId, Reads.ReadAlignment.class);
}
public <T> AlignmentIterator<T> iterator(String studyIdStr, String fileIdStr, Query query, QueryOptions options, String sessionId,
Class<T> clazz) throws CatalogException, IOException, StorageEngineException {
query = ParamUtils.defaultObject(query, Query::new);
options = ParamUtils.defaultObject(options, QueryOptions::new);
StudyInfo studyInfo = getStudyInfo(studyIdStr, fileIdStr, sessionId);
checkAlignmentBioformat(studyInfo.getFileInfos());
// ObjectMap fileAndStudyId = getFileAndStudyId(studyIdStr, fileIdStr, sessionId);
// long fileId = fileAndStudyId.getLong("fileId");
// Path filePath = getFilePath(fileId, sessionId);
return alignmentStorageManager.getDBAdaptor().iterator(studyInfo.getFileInfo().getPath(), query, options, clazz);
// return alignmentDBAdaptor.iterator((Path) fileInfo.get("filePath"), query, options, clazz);
}
public QueryResult<AlignmentGlobalStats> stats(String studyIdStr, String fileIdStr, Query query, QueryOptions options, String sessionId)
throws Exception {
query = ParamUtils.defaultObject(query, Query::new);
options = ParamUtils.defaultObject(options, QueryOptions::new);
StudyInfo studyInfo = getStudyInfo(studyIdStr, fileIdStr, sessionId);
checkAlignmentBioformat(studyInfo.getFileInfos());
FileInfo fileInfo = studyInfo.getFileInfo();
// ObjectMap fileAndStudyId = getFileAndStudyId(studyIdStr, fileIdStr, sessionId);
// long studyId = fileAndStudyId.getLong("studyId");
// long fileId = fileAndStudyId.getLong("fileId");
if (query.isEmpty() && options.isEmpty()) {
QueryOptions includeOptions = new QueryOptions(QueryOptions.INCLUDE, FileDBAdaptor.QueryParams.STATS.key());
QueryResult<File> fileQueryResult = catalogManager.getFileManager().get(fileInfo.getFileId(), includeOptions, sessionId);
logger.info("Obtaining the stats from catalog...");
if (fileQueryResult.getNumResults() == 1) {
Map<String, Object> stats = fileQueryResult.first().getStats();
Object value = stats.get(GLOBAL_STATS);
if (value != null && value instanceof String) {
ObjectReader reader = new ObjectMapper().reader(AlignmentGlobalStats.class);
AlignmentGlobalStats globalStats = reader.readValue((String) value);
return new QueryResult<>("Get stats", fileQueryResult.getDbTime(), 1, 1, fileQueryResult.getWarningMsg(),
fileQueryResult.getErrorMsg(), Arrays.asList(globalStats));
}
}
}
// Calculate the stats
logger.info("Calculating the stats...");
// Path filePath = getFilePath(fileId, sessionId);
// Path workspace = getWorkspace(studyId, sessionId);
return alignmentStorageManager.getDBAdaptor().stats(fileInfo.getPath(), studyInfo.getWorkspace(), query, options);
// return alignmentDBAdaptor.stats((Path) fileInfo.get("filePath"), (Path) fileInfo.get("workspace"), query, options);
}
public QueryResult<RegionCoverage> coverage(String studyIdStr, String fileIdStr, Query query, QueryOptions options, String sessionId)
throws Exception {
query = ParamUtils.defaultObject(query, Query::new);
options = ParamUtils.defaultObject(options, QueryOptions::new);
StudyInfo studyInfo = getStudyInfo(studyIdStr, fileIdStr, sessionId);
checkAlignmentBioformat(studyInfo.getFileInfos());
FileInfo fileInfo = studyInfo.getFileInfo();
// ObjectMap fileAndStudyId = getFileAndStudyId(studyIdStr, fileIdStr, sessionId);
// long studyId = fileAndStudyId.getLong("studyId");
// long fileId = fileAndStudyId.getLong("fileId");
// Path filePath = getFilePath(fileId, sessionId);
// Path workspace = getWorkspace(studyId, sessionId);
return alignmentStorageManager.getDBAdaptor().coverage(fileInfo.getPath(), studyInfo.getWorkspace(), query, options);
// return alignmentDBAdaptor.coverage((Path) fileInfo.get("filePath"), (Path) fileInfo.get("workspace"), query, options);
}
public QueryResult<Long> count(String studyIdStr, String fileIdStr, Query query, QueryOptions options, String sessionId)
throws CatalogException, IOException, StorageEngineException {
query = ParamUtils.defaultObject(query, Query::new);
options = ParamUtils.defaultObject(options, QueryOptions::new);
StudyInfo studyInfo = getStudyInfo(studyIdStr, fileIdStr, sessionId);
// ObjectMap fileAndStudyId = getFileAndStudyId(studyIdStr, fileIdStr, sessionId);
// long fileId = fileAndStudyId.getLong("fileId");
// Path filePath = getFilePath(fileId, sessionId);
return alignmentStorageManager.getDBAdaptor().count(studyInfo.getFileInfo().getPath(), query, options);
}
private void checkAlignmentBioformat(List<FileInfo> fileInfo) throws CatalogException {
for (FileInfo file : fileInfo) {
if (!file.getBioformat().equals(File.Bioformat.ALIGNMENT)) {
throw new CatalogException("File " + file.getName() + " not supported. Expecting an alignment file.");
}
}
}
@Override
public void testConnection() throws StorageEngineException {
}
@Deprecated
private Path getFilePath(long fileId, String sessionId) throws CatalogException, IOException {
QueryOptions fileOptions = new QueryOptions(QueryOptions.INCLUDE,
Arrays.asList(FileDBAdaptor.QueryParams.URI.key(), FileDBAdaptor.QueryParams.NAME.key()));
QueryResult<File> fileQueryResult = catalogManager.getFileManager().get(fileId, fileOptions, sessionId);
if (fileQueryResult.getNumResults() != 1) {
logger.error("Critical error: File {} not found in catalog.", fileId);
throw new CatalogException("Critical error: File " + fileId + " not found in catalog");
}
Path path = Paths.get(fileQueryResult.first().getUri().getRawPath());
FileUtils.checkFile(path);
return path;
}
@Deprecated
private Path getWorkspace(long studyId, String sessionId) throws CatalogException, IOException {
// Obtain the study uri
QueryOptions studyOptions = new QueryOptions(QueryOptions.INCLUDE, FileDBAdaptor.QueryParams.URI.key());
QueryResult<Study> studyQueryResult = catalogManager.getStudyManager().get(studyId, studyOptions, sessionId);
if (studyQueryResult .getNumResults() != 1) {
logger.error("Critical error: Study {} not found in catalog.", studyId);
throw new CatalogException("Critical error: Study " + studyId + " not found in catalog");
}
Path workspace = Paths.get(studyQueryResult.first().getUri().getRawPath()).resolve(".opencga").resolve("alignments");
if (!workspace.toFile().exists()) {
Files.createDirectories(workspace);
}
return workspace;
}
}