diff --git a/src/main/java/org/breedinginsight/brapi/v2/GermplasmController.java b/src/main/java/org/breedinginsight/brapi/v2/GermplasmController.java index 9981dbf51..ccd13c68d 100644 --- a/src/main/java/org/breedinginsight/brapi/v2/GermplasmController.java +++ b/src/main/java/org/breedinginsight/brapi/v2/GermplasmController.java @@ -21,6 +21,7 @@ import org.breedinginsight.brapi.v1.model.request.query.BrapiQuery; import org.breedinginsight.brapi.v2.model.response.mappers.GermplasmQueryMapper; import org.breedinginsight.brapi.v2.services.BrAPIGermplasmService; +import org.breedinginsight.brapps.importer.model.exports.FileType; import org.breedinginsight.model.DownloadFile; import org.breedinginsight.services.exceptions.DoesNotExistException; import org.breedinginsight.utilities.response.ResponseUtils; @@ -63,15 +64,16 @@ public HttpResponse>>> getGermplasm( } } - @Get("/${micronaut.bi.api.version}/programs/{programId}/germplasm/lists/{listDbId}/export") + @Get("/${micronaut.bi.api.version}/programs/{programId}/germplasm/lists/{listDbId}/export{?fileExtension}") @Produces(value = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") @ProgramSecured(roleGroups = {ProgramSecuredRoleGroup.ALL}) public HttpResponse germplasmListExport( - @PathVariable("programId") UUID programId, @PathVariable("listDbId") String listDbId) { + @PathVariable("programId") UUID programId, @PathVariable("listDbId") String listDbId, @QueryValue(defaultValue = "XLSX") String fileExtension) { String downloadErrorMessage = "An error occurred while generating the download file. Contact the development team at bidevteam@cornell.edu."; try { - DownloadFile germplasmListFile = germplasmService.exportGermplasmList(programId, listDbId); - HttpResponse germplasmListExport = HttpResponse.ok(germplasmListFile.getStreamedFile()).header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename="+germplasmListFile.getFileName()+".xlsx"); + FileType extension = Enum.valueOf(FileType.class, fileExtension); + DownloadFile germplasmListFile = germplasmService.exportGermplasmList(programId, listDbId, extension); + HttpResponse germplasmListExport = HttpResponse.ok(germplasmListFile.getStreamedFile()).header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename="+germplasmListFile.getFileName()+extension.getExtension()); return germplasmListExport; } catch (Exception e) { diff --git a/src/main/java/org/breedinginsight/brapi/v2/services/BrAPIGermplasmService.java b/src/main/java/org/breedinginsight/brapi/v2/services/BrAPIGermplasmService.java index b0c49b3bb..9d715e771 100644 --- a/src/main/java/org/breedinginsight/brapi/v2/services/BrAPIGermplasmService.java +++ b/src/main/java/org/breedinginsight/brapi/v2/services/BrAPIGermplasmService.java @@ -14,6 +14,7 @@ import org.brapi.v2.model.germ.BrAPIGermplasm; import org.brapi.v2.model.germ.BrAPIGermplasmSynonyms; import org.breedinginsight.brapps.importer.daos.BrAPIListDAO; +import org.breedinginsight.brapps.importer.model.exports.FileType; import org.breedinginsight.model.Column; import org.breedinginsight.model.DownloadFile; import org.breedinginsight.model.Pedigree; @@ -21,6 +22,7 @@ import org.breedinginsight.services.ProgramService; import org.breedinginsight.services.exceptions.DoesNotExistException; import org.breedinginsight.services.parsers.germplasm.GermplasmFileColumns; +import org.breedinginsight.services.writers.CSVWriter; import org.breedinginsight.services.writers.ExcelWriter; import org.breedinginsight.brapi.v2.dao.BrAPIGermplasmDAO; import org.breedinginsight.brapps.importer.model.ImportUpload; @@ -100,34 +102,14 @@ public List getGermplasmListsByProgramId(UUID programId, HttpR } } - public DownloadFile exportGermplasmList(UUID programId, String listId) throws ApiException, IOException { - List columns = GermplasmFileColumns.getOrderedColumns(); - - //Retrieve germplasm list data - BrAPIListDetails listData = brAPIListDAO.getListById(listId, programId).getResult(); - - //Retrieve germplasm data - List germplasmNames = listData.getData(); - List germplasm = germplasmDAO.getGermplasmByRawName(germplasmNames, programId); - //processGermplasmForDisplay, numbers - germplasm.sort(Comparator.comparingInt(g -> g.getAdditionalInfo().get("importEntryNumber").getAsInt())); - - String listName = listData.getListName(); - Optional optionalProgram = programService.getById(programId); - if (optionalProgram.isPresent()) { - Program program = optionalProgram.get(); - listName = removeAppendedKey(listName, program.getKey()); - } - String fileName = createFileName(listData, listName); - - //Convert list data to List> data to pass into file writer + public List> processData(List germplasm){ List> processedData = new ArrayList<>(); for (BrAPIGermplasm germplasmEntry: germplasm) { HashMap row = new HashMap<>(); - row.put("GID", Double.valueOf(germplasmEntry.getAccessionNumber())); + row.put("GID", Integer.valueOf(germplasmEntry.getAccessionNumber())); row.put("Name", germplasmEntry.getGermplasmName()); - row.put("Entry No", germplasmEntry.getAdditionalInfo().get("importEntryNumber").getAsDouble()); + row.put("Entry No", germplasmEntry.getAdditionalInfo().get("importEntryNumber").getAsInt()); row.put("Breeding Method", germplasmEntry.getAdditionalInfo().get("breedingMethod").getAsString()); String source = germplasmEntry.getSeedSource(); row.put("Source", source); @@ -143,8 +125,8 @@ public DownloadFile exportGermplasmList(UUID programId, String listId) throws Ap if ((germplasmEntry.getPedigree() != null) && (!germplasmEntry.getPedigree().isEmpty())) { Pedigree germPedigree = Pedigree.parsePedigreeString(germplasmEntry.getPedigree()); - row.put("Female Parent GID", Double.parseDouble(germPedigree.femaleParent)); - if (!germPedigree.maleParent.isEmpty()) row.put("Male Parent GID", Double.parseDouble(germPedigree.maleParent)); + row.put("Female Parent GID", Integer.parseInt(germPedigree.femaleParent)); + if (!germPedigree.maleParent.isEmpty()) row.put("Male Parent GID", Integer.parseInt(germPedigree.maleParent)); } // Synonyms @@ -157,8 +139,37 @@ public DownloadFile exportGermplasmList(UUID programId, String listId) throws Ap processedData.add(row); } + return processedData; + } + + public DownloadFile exportGermplasmList(UUID programId, String listId, FileType fileExtension) throws ApiException, IOException { + List columns = GermplasmFileColumns.getOrderedColumns(); + + //Retrieve germplasm list data + BrAPIListDetails listData = brAPIListDAO.getListById(listId, programId).getResult(); + + //Retrieve germplasm data + List germplasmNames = listData.getData(); + List germplasm = germplasmDAO.getGermplasmByRawName(germplasmNames, programId); + //processGermplasmForDisplay, numbers + germplasm.sort(Comparator.comparingInt(g -> g.getAdditionalInfo().get("importEntryNumber").getAsInt())); + + String listName = listData.getListName(); + Optional optionalProgram = programService.getById(programId); + if (optionalProgram.isPresent()) { + Program program = optionalProgram.get(); + listName = removeAppendedKey(listName, program.getKey()); + } + String fileName = createFileName(listData, listName); + StreamedFile downloadFile; + //Convert list data to List> data to pass into file writer + List> processedData = processData(germplasm); - StreamedFile downloadFile = ExcelWriter.writeToDownload("Germplasm Import", columns, processedData); + if (fileExtension == FileType.CSV){ + downloadFile = CSVWriter.writeToDownload(columns, processedData, fileExtension); + } else { + downloadFile = ExcelWriter.writeToDownload("Germplasm Import", columns, processedData, fileExtension); + } return new DownloadFile(fileName, downloadFile); } diff --git a/src/main/java/org/breedinginsight/brapps/importer/model/exports/FileType.java b/src/main/java/org/breedinginsight/brapps/importer/model/exports/FileType.java new file mode 100644 index 000000000..f3a81ecca --- /dev/null +++ b/src/main/java/org/breedinginsight/brapps/importer/model/exports/FileType.java @@ -0,0 +1,40 @@ +/* + * See the NOTICE file distributed with this work for additional information + * regarding copyright ownership. + * + * 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.breedinginsight.brapps.importer.model.exports; + +import lombok.Getter; + +/** +Defines MediaType parameters for file export + */ +@Getter +public enum FileType { + XLS("xls", ".xls", "application/vnd.ms-excel"), + XLSX("xlsx", ".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"), + CSV("csv", ".csv", "text/csv"); + + private String name; + private String extension; + private String mimeType; + + FileType(String name, String extension, String mimeType) { + this.name = name; + this.extension = extension; + this.mimeType = mimeType; + } +} \ No newline at end of file diff --git a/src/main/java/org/breedinginsight/model/Column.java b/src/main/java/org/breedinginsight/model/Column.java index bc4bfd3df..054dcb435 100644 --- a/src/main/java/org/breedinginsight/model/Column.java +++ b/src/main/java/org/breedinginsight/model/Column.java @@ -43,6 +43,7 @@ public Column(String value, ColumnDataType dataType) { //TODO add date if necessary public enum ColumnDataType { STRING, - NUMERICAL, + INTEGER, + DOUBLE } } diff --git a/src/main/java/org/breedinginsight/services/parsers/germplasm/GermplasmFileColumns.java b/src/main/java/org/breedinginsight/services/parsers/germplasm/GermplasmFileColumns.java index 79710343e..632b1f42d 100644 --- a/src/main/java/org/breedinginsight/services/parsers/germplasm/GermplasmFileColumns.java +++ b/src/main/java/org/breedinginsight/services/parsers/germplasm/GermplasmFileColumns.java @@ -18,23 +18,21 @@ import org.breedinginsight.model.Column; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Set; import java.util.stream.Collectors; public enum GermplasmFileColumns { - GID("GID", Column.ColumnDataType.NUMERICAL), + GID("GID", Column.ColumnDataType.INTEGER), NAME("Name", Column.ColumnDataType.STRING), BREEDING_METHOD("Breeding Method", Column.ColumnDataType.STRING), SOURCE("Source", Column.ColumnDataType.STRING), - FEMALE_PARENT_GID("Female Parent GID", Column.ColumnDataType.NUMERICAL), - MALE_PARENT_GID("Male Parent GID", Column.ColumnDataType.NUMERICAL), - ENTRY_NO("Entry No", Column.ColumnDataType.NUMERICAL), - FEMALE_PARENT_ENTRY_NO("Female Parent Entry No", Column.ColumnDataType.NUMERICAL), - MALE_PARENT_ENTRY_NO("Male Parent Entry No", Column.ColumnDataType.NUMERICAL), + FEMALE_PARENT_GID("Female Parent GID", Column.ColumnDataType.INTEGER), + MALE_PARENT_GID("Male Parent GID", Column.ColumnDataType.INTEGER), + ENTRY_NO("Entry No", Column.ColumnDataType.INTEGER), + FEMALE_PARENT_ENTRY_NO("Female Parent Entry No", Column.ColumnDataType.INTEGER), + MALE_PARENT_ENTRY_NO("Male Parent Entry No", Column.ColumnDataType.INTEGER), EXTERNAL_UID("External UID", Column.ColumnDataType.STRING), SYNONYMS("Synonyms", Column.ColumnDataType.STRING); diff --git a/src/main/java/org/breedinginsight/services/writers/CSVWriter.java b/src/main/java/org/breedinginsight/services/writers/CSVWriter.java new file mode 100644 index 000000000..d908b3052 --- /dev/null +++ b/src/main/java/org/breedinginsight/services/writers/CSVWriter.java @@ -0,0 +1,80 @@ +/* + * See the NOTICE file distributed with this work for additional information + * regarding copyright ownership. + * + * 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.breedinginsight.services.writers; + +import io.micronaut.http.MediaType; +import io.micronaut.http.server.types.files.StreamedFile; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.csv.CSVFormat; +import org.apache.commons.csv.CSVPrinter; +import org.breedinginsight.brapps.importer.model.exports.FileType; +import org.breedinginsight.model.Column; +import org.jetbrains.annotations.NotNull; + +import java.io.*; +import java.util.*; + +/* + * This csv writer creates a csv file with the first row as column names and subsequent rows + * as data. + */ +@Slf4j +public class CSVWriter { + + public static StreamedFile writeToDownload(List columns, List> data, FileType extension) throws IOException { + try (ByteArrayOutputStream out = writeToCSV(columns, data)) { + InputStream inputStream = new ByteArrayInputStream(out.toByteArray()); + MediaType fileVal = new MediaType(extension.getMimeType(), extension.getName()); + StreamedFile downloadFile = new StreamedFile(inputStream, fileVal); + return downloadFile; + } catch (IOException e) { + log.info(e.getMessage()); + throw e; + } + } + + //Writes to csv with desired columns and data + public static ByteArrayOutputStream writeToCSV(List columns, List> data) { + + String[] headers = columns.stream().map(x -> x.getValue() ).toArray(String[]::new); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + try { + CSVFormat format = CSVFormat.EXCEL.withHeader(headers); + CSVPrinter csvPrinter = new CSVPrinter(new PrintWriter(out), format); + + ArrayList rowVals; + Object cellValue; + for (int i = 0; i < data.size(); i++) { + rowVals = new ArrayList<>(); + for (Column column: columns) { + if(data.get(i).containsKey(column.getValue())){ + cellValue = data.get(i).get(column.getValue()); + rowVals.add(cellValue); + } else { + rowVals.add(""); + } + } + csvPrinter.printRecord(rowVals); + } + csvPrinter.close(); + } catch (IOException e) { + + } + return out; + } +} diff --git a/src/main/java/org/breedinginsight/services/writers/ExcelWriter.java b/src/main/java/org/breedinginsight/services/writers/ExcelWriter.java index 4f35624cc..3651281f5 100644 --- a/src/main/java/org/breedinginsight/services/writers/ExcelWriter.java +++ b/src/main/java/org/breedinginsight/services/writers/ExcelWriter.java @@ -3,10 +3,15 @@ import io.micronaut.http.MediaType; import io.micronaut.http.server.types.files.StreamedFile; import lombok.extern.slf4j.Slf4j; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.xssf.usermodel.XSSFSheet; import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.breedinginsight.brapps.importer.model.exports.FileType; import org.breedinginsight.model.Column; +import org.jetbrains.annotations.NotNull; import java.io.*; import java.util.*; @@ -21,12 +26,21 @@ public class ExcelWriter { private static final int EXCEL_COLUMN_NAMES_ROW = 0; //Writes a xlsx workbook with one sheet with desired columns and data - public static XSSFWorkbook writeToWorkbook(String sheetName, List columns, List> data) { + public static Workbook writeToWorkbook(String sheetName, List columns, List> data, FileType extension) { + Workbook workbook; + Sheet sheet; + //Create workbook - XSSFWorkbook workbook = new XSSFWorkbook(); + if (extension == FileType.XLSX){ + workbook = new XSSFWorkbook(); + } else if (extension == FileType.XLS) { + workbook = new HSSFWorkbook(); + } else { + throw new IllegalArgumentException(extension.getName()+" is invalid file extension for excel."); + } //Create sheet - XSSFSheet sheet = workbook.createSheet(sheetName); + sheet = workbook.createSheet(sheetName); //Fill in header and data int cellCount; @@ -42,7 +56,9 @@ public static XSSFWorkbook writeToWorkbook(String sheetName, List column if (data.get(i-1).get(column.getValue()) != null) { if (column.getDataType() == Column.ColumnDataType.STRING) { row.createCell(cellCount).setCellValue((String) data.get(i - 1).get(column.getValue())); - } else if (column.getDataType() == Column.ColumnDataType.NUMERICAL) { + } else if (column.getDataType() == Column.ColumnDataType.INTEGER) { + row.createCell(cellCount).setCellValue((Integer) data.get(i - 1).get(column.getValue())); + } else if (column.getDataType() == Column.ColumnDataType.DOUBLE) { row.createCell(cellCount).setCellValue((Double) data.get(i - 1).get(column.getValue())); } } else { @@ -57,13 +73,13 @@ public static XSSFWorkbook writeToWorkbook(String sheetName, List column return workbook; } - public static StreamedFile writeToDownload(String sheetName, List columns, List> data) throws IOException { - XSSFWorkbook workbook = writeToWorkbook(sheetName, columns, data); + public static StreamedFile writeToDownload(String sheetName, List columns, List> data, FileType extension) throws IOException { + Workbook workbook = writeToWorkbook(sheetName, columns, data, extension); try (ByteArrayOutputStream out = new ByteArrayOutputStream()) { workbook.write(out); InputStream inputStream = new ByteArrayInputStream(out.toByteArray()); - MediaType fileVal = new MediaType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "xlsx"); + MediaType fileVal = new MediaType(extension.getMimeType(), extension.getName()); StreamedFile downloadFile = new StreamedFile(inputStream, fileVal); return downloadFile; } catch (IOException e) { @@ -73,8 +89,8 @@ public static StreamedFile writeToDownload(String sheetName, List column } //For unit testing - public static InputStream writeToInputStream(String sheetName, List columns, List> data) throws IOException { - XSSFWorkbook workbook = writeToWorkbook(sheetName, columns, data); + public static InputStream writeToInputStream(String sheetName, List columns, List> data, FileType extension) throws IOException { + Workbook workbook = writeToWorkbook(sheetName, columns, data, extension); try (ByteArrayOutputStream out = new ByteArrayOutputStream()) { workbook.write(out); @@ -86,10 +102,10 @@ public static InputStream writeToInputStream(String sheetName, List colu } //Writes doc to file in project, for optional testing - public static void writeToFile(String fileName, String sheetName, List columns, List> data) throws IOException { - XSSFWorkbook workbook = writeToWorkbook(sheetName, columns, data); + public static void writeToFile(String fileName, String sheetName, List columns, List> data, FileType extension) throws IOException { + Workbook workbook = writeToWorkbook(sheetName, columns, data, extension); - try (FileOutputStream fileOutput = new FileOutputStream(fileName +".xlsx")) { + try (FileOutputStream fileOutput = new FileOutputStream(fileName + extension.getExtension())) { workbook.write(fileOutput); workbook.close(); } catch (IOException e) { diff --git a/src/test/java/org/breedinginsight/utilities/response/FileUtilUnitTest.java b/src/test/java/org/breedinginsight/utilities/response/FileUtilUnitTest.java index b2cf7792f..ad36d4f64 100644 --- a/src/test/java/org/breedinginsight/utilities/response/FileUtilUnitTest.java +++ b/src/test/java/org/breedinginsight/utilities/response/FileUtilUnitTest.java @@ -1,6 +1,7 @@ package org.breedinginsight.utilities.response; import lombok.SneakyThrows; +import org.breedinginsight.brapps.importer.model.exports.FileType; import org.breedinginsight.model.Column; import org.breedinginsight.services.parsers.ParsingException; import org.breedinginsight.services.parsers.ParsingExceptionType; @@ -64,7 +65,7 @@ void parseExcelNoRemoveSomeNullRows() { void writeExcelCheckColumns() { List columns = new ArrayList<>(); columns.add(new Column("Test A", Column.ColumnDataType.STRING)); - columns.add(new Column("Test B", Column.ColumnDataType.NUMERICAL)); + columns.add(new Column("Test B", Column.ColumnDataType.INTEGER)); columns.add(new Column("Test C", Column.ColumnDataType.STRING)); List columnNames = new ArrayList<>(); @@ -75,11 +76,11 @@ void writeExcelCheckColumns() { List> data = new ArrayList<>(); HashMap row = new HashMap<>(); row.put("Test A", "Data A"); - row.put("Test B", Double.valueOf("2")); + row.put("Test B", Integer.valueOf("2")); row.put("Test C", "C"); data.add(row); - InputStream inputStream = ExcelWriter.writeToInputStream("SheetName", columns, data); + InputStream inputStream = ExcelWriter.writeToInputStream("SheetName", columns, data, FileType.XLSX); Table resultTable = FileUtil.parseTableFromExcel(inputStream, 0); assertEquals(1, resultTable.rowCount(), "Wrong number of rows were exported");