diff --git a/src/main/java/org/breedinginsight/brapi/v2/services/BrAPITrialService.java b/src/main/java/org/breedinginsight/brapi/v2/services/BrAPITrialService.java index 2560d1285..b902132ad 100644 --- a/src/main/java/org/breedinginsight/brapi/v2/services/BrAPITrialService.java +++ b/src/main/java/org/breedinginsight/brapi/v2/services/BrAPITrialService.java @@ -11,6 +11,7 @@ import org.brapi.v2.model.core.*; import org.brapi.v2.model.core.response.BrAPIListsSingleResponse; import org.brapi.v2.model.germ.BrAPIGermplasm; + import org.brapi.v2.model.pheno.*; import org.breedinginsight.brapi.v2.constants.BrAPIAdditionalInfoFields; import org.breedinginsight.brapi.v2.dao.BrAPIGermplasmDAO; @@ -18,6 +19,7 @@ import org.breedinginsight.brapps.importer.daos.*; import org.breedinginsight.brapps.importer.model.exports.FileType; import org.breedinginsight.brapps.importer.model.imports.experimentObservation.ExperimentObservation; +import org.breedinginsight.brapps.importer.model.imports.experimentObservation.ExperimentObservation.Columns; import org.breedinginsight.brapps.importer.services.ExternalReferenceSource; import org.breedinginsight.brapps.importer.services.FileMappingUtil; import org.breedinginsight.model.BrAPIConstants; @@ -29,7 +31,9 @@ import org.breedinginsight.services.parsers.experiment.ExperimentFileColumns; import org.breedinginsight.services.writers.CSVWriter; import org.breedinginsight.services.writers.ExcelWriter; +import org.breedinginsight.utilities.IntOrderComparator; import org.breedinginsight.utilities.Utilities; +import org.jetbrains.annotations.NotNull; import javax.inject.Inject; import javax.inject.Singleton; @@ -57,6 +61,7 @@ public class BrAPITrialService { private final BrAPIObservationUnitDAO ouDAO; private final BrAPIGermplasmDAO germplasmDAO; private final FileMappingUtil fileMappingUtil; + private static final String SHEET_NAME = "Data"; @Inject public BrAPITrialService(@Property(name = "brapi.server.reference-source") String referenceSource, @@ -227,7 +232,7 @@ public DownloadFile exportObservations( // Initialize key with empty list if it is not present. if (!rowsByStudyId.containsKey(studyId)) { - rowsByStudyId.put(studyId, new ArrayList>()); + rowsByStudyId.put(studyId, new ArrayList<>()); } // Add row to appropriate list in rowsByStudyId. rowsByStudyId.get(studyId).add(row); @@ -235,7 +240,9 @@ public DownloadFile exportObservations( List files = new ArrayList<>(); // Generate a file for each study. for (Map.Entry>> entry: rowsByStudyId.entrySet()) { - StreamedFile streamedFile = writeToStreamedFile(columns, entry.getValue(), fileType, "Experiment Data"); + List> rows = entry.getValue(); + sortDefaultForExportRows(rows); + StreamedFile streamedFile = writeToStreamedFile(columns, rows, fileType, SHEET_NAME); String name = makeFileName(experiment, program, studyByDbId.get(entry.getKey()).getStudyName()) + fileType.getExtension(); // Add to file list. files.add(new DownloadFile(name, streamedFile)); @@ -252,8 +259,9 @@ public DownloadFile exportObservations( } } else { List> exportRows = new ArrayList<>(rowByOUId.values()); + sortDefaultForExportRows(exportRows); // write export data to requested file format - StreamedFile streamedFile = writeToStreamedFile(columns, exportRows, fileType, "Experiment Data"); + StreamedFile streamedFile = writeToStreamedFile(columns, exportRows, fileType, SHEET_NAME); // Set filename. String envFilenameFragment = params.getEnvironments() == null ? "All Environments" : params.getEnvironments(); String fileName = makeFileName(experiment, program, envFilenameFragment) + fileType.getExtension(); @@ -308,6 +316,7 @@ public Dataset getDatasetData(Program program, UUID experimentId, UUID datsetId, log.debug("fetching observations for dataset: " + datsetId); List data = observationDAO.getObservationsByObservationUnitsAndVariables(ouDbIds, obsVarDbIds, program); log.debug("building dataset object for dataset: " + datsetId); + sortDefaultForObservationUnit(datasetOUs); Dataset dataset = new Dataset(experimentId.toString(), data, datasetOUs, datasetObsVars); if (stats) { Integer ouCount = datasetOUs.size(); @@ -551,4 +560,17 @@ private List filterDatasetByEnvironment( .collect(Collectors.toList()); } -} \ No newline at end of file + private void sortDefaultForObservationUnit(List ous) { + Comparator studyNameComparator = Comparator.comparing(BrAPIObservationUnit::getStudyName, new IntOrderComparator()); + Comparator ouNameComparator = Comparator.comparing(BrAPIObservationUnit::getObservationUnitName, new IntOrderComparator()); + ous.sort( (studyNameComparator).thenComparing(ouNameComparator)); + } + + private void sortDefaultForExportRows(@NotNull List> exportRows) { + Comparator> envComparator = Comparator.comparing(row -> (row.get(Columns.ENV).toString()), new IntOrderComparator()); + Comparator> expUnitIdComparator = + Comparator.comparing(row -> (row.get(Columns.EXP_UNIT_ID).toString()), new IntOrderComparator()); + + exportRows.sort(envComparator.thenComparing(expUnitIdComparator)); + } +} diff --git a/src/main/java/org/breedinginsight/utilities/IntOrderComparator.java b/src/main/java/org/breedinginsight/utilities/IntOrderComparator.java new file mode 100644 index 000000000..bbd1ca813 --- /dev/null +++ b/src/main/java/org/breedinginsight/utilities/IntOrderComparator.java @@ -0,0 +1,84 @@ +package org.breedinginsight.utilities; + +import java.math.BigInteger; +import java.util.Comparator; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +/* +If you have text(optional), followed by some digits(optional), followed by more text(optional), this Comparator +will sort the digits in numeric order. The trailing text (and any subsequent digits) will be in +alpha-numeric order. + +In other words; this comparator will assume that strings being compared are comprised of a text _prefix_, followed by +_digits_, followed by a _suffix_. + +This comparator will fist compare the prefix as an alpha-numeric, the digits as a numeric and +then the the suffix as an alpha-numeric. +For Example: +1) if a string is 'big4team', then prefix='big', digits=4, suffix='team' +2) if a string is '12monkeys', then prefix='', digits=12, suffix='monkeys' +3) if a string is 'abcd', then prefix='abcd', digits=null, suffix='' +4) if a string is 'libnum14.3', then prefix='libnum', digits=14, suffix='.4' +*/ +public class IntOrderComparator implements Comparator { + @Override + public int compare(String str1, String str2) { + //static finals to make the Matcher::group code more readable + final int PREFIX = 1; + final int DIGITS = 2; + final int SUFFIX = 3; + + // convert null strings to blank + str1 = (str1 == null) ? "" : str1; + str2 = (str2 == null) ? "" : str2; + + //The real work begins + + // NOTE: The last group includes all remaining text and digits + Pattern p = Pattern.compile("^([^\\d]*)(\\d*)(.*)$"); + + Matcher m1 = p.matcher(str1); + Matcher m2 = p.matcher(str2); + + m1.find(); // needed to let m1.group() work + m2.find(); // needed to let m2.group() work + + String prefix1 = m1.group(PREFIX); + String prefix2 = m2.group(PREFIX); + BigInteger digits1 = m1.group(DIGITS).length() > 0 ? new BigInteger(m1.group(DIGITS)) : null; + BigInteger digits2 = m2.group(DIGITS).length() > 0 ? new BigInteger(m2.group(DIGITS)) : null; + String suffix1 = m1.group(SUFFIX); + String suffix2 = m2.group(SUFFIX); + + if (!prefix1.equals(prefix2)) { + return prefix1.compareTo(prefix2); + } + /*if the prefixes are equal, sort by digits and suffixes.*/ + + // an empty digit is less than any digit (EX. 'a' is less than 'a1') + if( digits1 == null){ + if(digits2 == null){ + return 0; //if both digits are null (equal) + } + else { + return -1; //if there are no digits in str1 but digits in str2 (str1 < str2) + } + } + if( digits2 == null){ + return 1; //if there are digits in str1 but no digits in str2 (str1 > str2) + } + if (!digits1.equals(digits2)) { + return digits1.compareTo(digits2); + } + /*if the prefixes and digits are equal, sort by suffixes.*/ + if (!suffix1.equals(suffix2)) { + return suffix1.compareTo(suffix2); + } + + /* if all else fails, compare the strings + (I think this will always return 0)*/ + return str1.compareTo(str2); + } +} + +