diff --git a/src/main/java/org/cbioportal/file/export/FileWriterFactory.java b/src/main/java/org/cbioportal/file/export/FileWriterFactory.java new file mode 100644 index 00000000000..29cfe3f7fee --- /dev/null +++ b/src/main/java/org/cbioportal/file/export/FileWriterFactory.java @@ -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; +} diff --git a/src/main/java/org/cbioportal/file/export/ZipOutputStreamWriterFactory.java b/src/main/java/org/cbioportal/file/export/ZipOutputStreamWriterFactory.java new file mode 100644 index 00000000000..27f23a53761 --- /dev/null +++ b/src/main/java/org/cbioportal/file/export/ZipOutputStreamWriterFactory.java @@ -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(); + } + } +} diff --git a/src/main/java/org/cbioportal/service/impl/ExportService.java b/src/main/java/org/cbioportal/service/impl/ExportService.java index a28d2bab613..519722aa35a 100644 --- a/src/main/java/org/cbioportal/service/impl/ExportService.java +++ b/src/main/java/org/cbioportal/service/impl/ExportService.java @@ -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 { @@ -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> molecularProfilesByStableId = this.molecularProfileService.getMolecularProfilesInStudies(cancerStudyInfo.studyToSampleMap.keySet().stream().toList(), "SUMMARY").stream().collect(Collectors.groupingBy(MolecularProfile::getStableId)); + for (Map.Entry> molecularProfiles : molecularProfilesByStableId.entrySet()) { + String stableId = molecularProfiles.getKey(); + List molecularProfileList = molecularProfiles.getValue(); + Map 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 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> molecularProfilesByStableId = this.molecularProfileService.getMolecularProfilesInStudies(cancerStudyInfo.studyToSampleMap.keySet().stream().toList(), "SUMMARY").stream().collect(Collectors.groupingBy(MolecularProfile::getStableId)); - for (Map.Entry> molecularProfiles : molecularProfilesByStableId.entrySet()) { - String stableId = molecularProfiles.getKey(); - List molecularProfileList = molecularProfiles.getValue(); - Map 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 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); } } } diff --git a/src/main/java/org/cbioportal/web/ExportController.java b/src/main/java/org/cbioportal/web/ExportController.java index 432e3b1496e..ccc8aaea338 100644 --- a/src/main/java/org/cbioportal/web/ExportController.java +++ b/src/main/java/org/cbioportal/web/ExportController.java @@ -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 { @@ -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); } } }