Skip to content

Commit

Permalink
Move zip specific logic to separate fileWriterFactory class
Browse files Browse the repository at this point in the history
  • Loading branch information
forus committed Dec 17, 2024
1 parent 1eaed1d commit 1dca600
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 81 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.cbioportal.file.export;

import java.io.IOException;
import java.io.Writer;

public interface FileWriterFactory {
Writer newWriter(String name) throws IOException;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package org.cbioportal.file.export;

import java.io.Closeable;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class ZipOutputStreamWriterFactory implements FileWriterFactory, Closeable {

private final ZipOutputStream zipOutputStream;

public ZipOutputStreamWriterFactory(OutputStream outputStream) {
this.zipOutputStream = new ZipOutputStream(outputStream);
}

@Override
public Writer newWriter(String name) throws IOException {
return new ZipEntryOutputStreamWriter(name, zipOutputStream);
}

@Override
public void close() throws IOException {
zipOutputStream.close();
}

static class ZipEntryOutputStreamWriter extends OutputStreamWriter {
private final ZipOutputStream zipOutputStream;

public ZipEntryOutputStreamWriter(String name, ZipOutputStream zipOutputStream) throws IOException {
super(zipOutputStream);
zipOutputStream.putNextEntry(new ZipEntry(name));
this.zipOutputStream = zipOutputStream;
}

@Override
public void close() throws IOException {
flush();
zipOutputStream.closeEntry();
}
}
}
125 changes: 53 additions & 72 deletions src/main/java/org/cbioportal/service/impl/ExportService.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@
import java.io.*;
import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@Service
public class ExportService {
Expand All @@ -46,85 +44,68 @@ public ExportService(StudyService studyService,
this.clinicalAttributeDataFetcher = clinicalAttributeDataFetcher;
}

class ZipEntryOutputStreamWriter extends OutputStreamWriter {
private final ZipOutputStream zipOutputStream;

public ZipEntryOutputStreamWriter(String name, ZipOutputStream zipOutputStream) throws IOException {
super(zipOutputStream);
zipOutputStream.putNextEntry(new ZipEntry(name));
this.zipOutputStream = zipOutputStream;
}

@Override
public void close() throws IOException {
flush();
zipOutputStream.closeEntry();
public void exportStudyData(FileWriterFactory fileWriterFactory, String studyId) throws IOException {
CancerStudyInfo cancerStudyInfo = getCancerStudyInfo(studyId);
try (Writer studyMetadataWriter = fileWriterFactory.newWriter("meta_study.txt")) {
new KeyValueMetadataWriter(studyMetadataWriter).write(cancerStudyInfo.metadata);
}
}

public void exportStudyDataToZip(OutputStream outputStream, String studyId) throws IOException {
CancerStudyInfo cancerStudyInfo = getCancerStudyInfo(studyId);
try (ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream)) {
// Add files to the ZIP
try (ZipEntryOutputStreamWriter studyMetadataWriter = new ZipEntryOutputStreamWriter("meta_study.txt", zipOutputStream)) {
new KeyValueMetadataWriter(studyMetadataWriter).write(cancerStudyInfo.metadata);
// TODO detect what data types are available for a study and export them
// by iterating over the available data types and calling the appropriate fetchers and writers
// the boiler plate code below should be replaced by the above logic

ClinicalAttributeData clinicalAttributeData = clinicalAttributeDataFetcher.fetch(cancerStudyInfo.studyToSampleMap);
if (clinicalAttributeData.rows().hasNext()) {
ClinicalSampleAttributesMetadata clinicalSampleAttributesMetadata = new ClinicalSampleAttributesMetadata(
studyId,
"data_clinical_samples.txt"
);
try (Writer clinicalSampleMetadataWriter = fileWriterFactory.newWriter("meta_clinical_samples.txt")) {
new KeyValueMetadataWriter(clinicalSampleMetadataWriter).write(clinicalSampleAttributesMetadata);
}

// TODO detect what data types are available for a study and export them
// by iterating over the available data types and calling the appropriate fetchers and writers
// the boiler plate code below should be replaced by the above logic

ClinicalAttributeData clinicalAttributeData = clinicalAttributeDataFetcher.fetch(cancerStudyInfo.studyToSampleMap);
if (clinicalAttributeData.rows().hasNext()) {
ClinicalSampleAttributesMetadata clinicalSampleAttributesMetadata = new ClinicalSampleAttributesMetadata(
studyId,
"data_clinical_samples.txt"
);
try (ZipEntryOutputStreamWriter clinicalSampleMetadataWriter = new ZipEntryOutputStreamWriter("meta_clinical_samples.txt", zipOutputStream)) {
new KeyValueMetadataWriter(clinicalSampleMetadataWriter).write(clinicalSampleAttributesMetadata);
}
try (Writer clinicalSampleDataWriter = fileWriterFactory.newWriter("data_clinical_samples.txt")) {
ClinicalAttributeDataWriter clinicalAttributeDataWriter = new ClinicalAttributeDataWriter(clinicalSampleDataWriter);
clinicalAttributeDataWriter.write(clinicalAttributeData);
}
}

try (ZipEntryOutputStreamWriter clinicalSampleDataWriter = new ZipEntryOutputStreamWriter("data_clinical_samples.txt", zipOutputStream)) {
ClinicalAttributeDataWriter clinicalAttributeDataWriter = new ClinicalAttributeDataWriter(clinicalSampleDataWriter);
clinicalAttributeDataWriter.write(clinicalAttributeData);
}
Map<String, List<MolecularProfile>> molecularProfilesByStableId = this.molecularProfileService.getMolecularProfilesInStudies(cancerStudyInfo.studyToSampleMap.keySet().stream().toList(), "SUMMARY").stream().collect(Collectors.groupingBy(MolecularProfile::getStableId));
for (Map.Entry<String, List<MolecularProfile>> molecularProfiles : molecularProfilesByStableId.entrySet()) {
String stableId = molecularProfiles.getKey();
List<MolecularProfile> molecularProfileList = molecularProfiles.getValue();
Map<MolecularProfile.MolecularAlterationType, String> molecularAlterationTypeToDatatype = molecularProfileList.stream()
.collect(Collectors.toMap(MolecularProfile::getMolecularAlterationType, MolecularProfile::getDatatype));
if (molecularAlterationTypeToDatatype.size() > 1) {
throw new IllegalStateException("Molecular profiles with the same stable Id ("
+ stableId + ") have different molecular alteration types and datatypes:" + molecularAlterationTypeToDatatype);
}
if ("MAF".equals(molecularAlterationTypeToDatatype.get(MolecularProfile.MolecularAlterationType.MUTATION_EXTENDED))) {
Iterator<MafRecord> mafRecordIterator = mafRecordFetcher.fetch(cancerStudyInfo.studyToSampleMap, stableId);
if (mafRecordIterator.hasNext()) {
GenericProfileDatatypeMetadata genericProfileDatatypeMetadata = new GenericProfileDatatypeMetadata(
stableId,
//TODO Use mol. alteration type and datatype from the map above instead
MolecularProfile.MolecularAlterationType.MUTATION_EXTENDED.toString(),
"MAF",
studyId,
"data_mutations.txt",
molecularProfileList.getFirst().getName(),
molecularProfileList.getFirst().getDescription(),
//TODO where to get gene panel from?
Optional.empty(),
//Is it true for all data types?
true
);
try (Writer mafMetaWriter = fileWriterFactory.newWriter("meta_mutations.txt")) {
new KeyValueMetadataWriter(mafMetaWriter).write(genericProfileDatatypeMetadata);
}

Map<String, List<MolecularProfile>> molecularProfilesByStableId = this.molecularProfileService.getMolecularProfilesInStudies(cancerStudyInfo.studyToSampleMap.keySet().stream().toList(), "SUMMARY").stream().collect(Collectors.groupingBy(MolecularProfile::getStableId));
for (Map.Entry<String, List<MolecularProfile>> molecularProfiles : molecularProfilesByStableId.entrySet()) {
String stableId = molecularProfiles.getKey();
List<MolecularProfile> molecularProfileList = molecularProfiles.getValue();
Map<MolecularProfile.MolecularAlterationType, String> molecularAlterationTypeToDatatype = molecularProfileList.stream()
.collect(Collectors.toMap(MolecularProfile::getMolecularAlterationType, MolecularProfile::getDatatype));
if (molecularAlterationTypeToDatatype.size() > 1) {
throw new IllegalStateException("Molecular profiles with the same stable Id ("
+ stableId + ") have different molecular alteration types and datatypes:" + molecularAlterationTypeToDatatype);
}
if ("MAF".equals(molecularAlterationTypeToDatatype.get(MolecularProfile.MolecularAlterationType.MUTATION_EXTENDED))) {
Iterator<MafRecord> mafRecordIterator = mafRecordFetcher.fetch(cancerStudyInfo.studyToSampleMap, stableId);
if (mafRecordIterator.hasNext()) {
GenericProfileDatatypeMetadata genericProfileDatatypeMetadata = new GenericProfileDatatypeMetadata(
stableId,
//TODO Use mol. alteration type and datatype from the map above instead
MolecularProfile.MolecularAlterationType.MUTATION_EXTENDED.toString(),
"MAF",
studyId,
"data_mutations.txt",
molecularProfileList.getFirst().getName(),
molecularProfileList.getFirst().getDescription(),
//TODO where to get gene panel from?
Optional.empty(),
//Is it true for all data types?
true
);
try (ZipEntryOutputStreamWriter mafMetaWriter = new ZipEntryOutputStreamWriter("meta_mutations.txt", zipOutputStream)) {
new KeyValueMetadataWriter(mafMetaWriter).write(genericProfileDatatypeMetadata);
}

try (ZipEntryOutputStreamWriter mafDataWriter = new ZipEntryOutputStreamWriter("data_mutations.txt", zipOutputStream)) {
MafRecordWriter mafRecordWriter = new MafRecordWriter(mafDataWriter);
mafRecordWriter.write(mafRecordIterator);
}
try (Writer mafDataWriter = fileWriterFactory.newWriter("data_mutations.txt")) {
MafRecordWriter mafRecordWriter = new MafRecordWriter(mafDataWriter);
mafRecordWriter.write(mafRecordIterator);
}
}
}
Expand Down
13 changes: 4 additions & 9 deletions src/main/java/org/cbioportal/web/ExportController.java
Original file line number Diff line number Diff line change
@@ -1,21 +1,15 @@
package org.cbioportal.web;

import jakarta.servlet.http.HttpServletResponse;
import org.cbioportal.file.export.ZipOutputStreamWriterFactory;
import org.cbioportal.service.impl.ExportService;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@RestController
public class ExportController {
Expand All @@ -35,8 +29,9 @@ public void downloadStudyData(HttpServletResponse response, @PathVariable String
response.setHeader("Content-Disposition", "attachment; filename=\""+ studyId +".zip\"");

try (OutputStream out = response.getOutputStream();
BufferedOutputStream bof = new BufferedOutputStream(out)) {
exportService.exportStudyDataToZip(bof, studyId);
BufferedOutputStream bof = new BufferedOutputStream(out);
ZipOutputStreamWriterFactory zipOutputStreamWriterFactory = new ZipOutputStreamWriterFactory(bof)) {
exportService.exportStudyData(zipOutputStreamWriterFactory, studyId);
}
}
}

0 comments on commit 1dca600

Please sign in to comment.