Skip to content

Commit 1b70f5f

Browse files
committed
#13771 - Add Epipulse export functionality for Measles disease
1 parent ef17b1e commit 1b70f5f

2 files changed

Lines changed: 42 additions & 8 deletions

File tree

sormas-api/src/main/java/de/symeda/sormas/api/epipulse/EpipulseLaboratoryMapper.java

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,13 @@ public static String normalizeGenotypeForEpipulse(String genotypeText) {
123123

124124
String normalized = genotypeText.trim().toUpperCase();
125125

126-
// If already in MEASV_ format, return as-is
126+
// If already in MEASV_ format, validate the suffix and return if valid
127127
if (normalized.startsWith("MEASV_")) {
128-
return normalized;
128+
String suffix = normalized.substring(6); // Extract part after "MEASV_"
129+
if (isValidMeaslesGenotype(suffix)) {
130+
return normalized;
131+
}
132+
return null;
129133
}
130134

131135
// Try to parse formats like "A", "B1", "D10", etc. and add MEASV_ prefix
@@ -137,14 +141,28 @@ public static String normalizeGenotypeForEpipulse(String genotypeText) {
137141
// Try to extract genotype from common formats with delimiters
138142
// Matches patterns like "MeV-A", "Genotype-B1", "MV/A", "MEASLES-D4"
139143
String extracted = extractGenotypeFromDelimitedFormat(normalized);
140-
if (extracted != null) {
144+
if (isValidMeaslesGenotype(extracted)) {
141145
return "MEASV_" + extracted;
142146
}
143147

144148
// Return null for ambiguous or unparseable inputs
145149
return null;
146150
}
147151

152+
/**
153+
* Validates if a genotype code matches the known measles genotype pattern.
154+
*
155+
* @param genotype
156+
* Genotype code without MEASV_ prefix (e.g., "A", "B1", "D10")
157+
* @return true if the genotype is a valid measles genotype, false otherwise
158+
*/
159+
private static boolean isValidMeaslesGenotype(String genotype) {
160+
if (genotype == null) {
161+
return false;
162+
}
163+
return genotype.matches("^(A|B[1-3]|C[1-2]|D(1[0-1]|[1-9])|E|F|G[1-3]|H[1-2])$");
164+
}
165+
148166
/**
149167
* Extracts genotype code from delimited formats like "MeV-A", "Genotype B1", etc.
150168
* Uses strict pattern matching to avoid false positives.

sormas-backend/src/main/java/de/symeda/sormas/backend/epipulse/EpipulseCsvExportOrchestrator.java

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ public class EpipulseCsvExportOrchestrator {
7676
public void orchestrateExport(String uuid, ExportFunction exportFunction, CsvExportStrategy csvStrategy) {
7777

7878
CSVWriter writer = null;
79+
FileOutputStream fos = null;
80+
OutputStreamWriter osw = null;
7981
EpipulseExport epipulseExport = null;
8082
EpipulseExportStatus exportStatus = EpipulseExportStatus.FAILED;
8183
boolean shouldUpdateStatus = false;
@@ -117,10 +119,10 @@ public void orchestrateExport(String uuid, ExportFunction exportFunction, CsvExp
117119
EpipulseDiseaseExportResult exportResult = exportFunction.execute(exportDto, serverCountryCode, serverCountryName);
118120
totalRecords = exportResult.getExportEntryList().size();
119121

120-
// Setup CSV writer
121-
writer = CSVUtils.createCSVWriter(
122-
new OutputStreamWriter(new FileOutputStream(exportFilePath), StandardCharsets.UTF_8),
123-
configFacadeEjb.getCsvSeparator());
122+
// Setup CSV writer with explicit stream management
123+
fos = new FileOutputStream(exportFilePath);
124+
osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8);
125+
writer = CSVUtils.createCSVWriter(osw, configFacadeEjb.getCsvSeparator());
124126

125127
// Build column names using strategy
126128
List<String> columnNames = csvStrategy.buildColumnNames(exportResult);
@@ -140,14 +142,28 @@ public void orchestrateExport(String uuid, ExportFunction exportFunction, CsvExp
140142
exportStatus = EpipulseExportStatus.FAILED;
141143
logger.error("Error during export with uuid " + uuid + ": " + e.getMessage(), e);
142144
} finally {
143-
// Close writer
145+
// Close resources in reverse order
144146
if (writer != null) {
145147
try {
146148
writer.close();
147149
} catch (Exception e) {
148150
logger.error("CRITICAL: Failed to close CSVWriter for uuid " + uuid + ": " + e.getMessage(), e);
149151
}
150152
}
153+
if (osw != null) {
154+
try {
155+
osw.close();
156+
} catch (Exception e) {
157+
logger.error("CRITICAL: Failed to close OutputStreamWriter for uuid " + uuid + ": " + e.getMessage(), e);
158+
}
159+
}
160+
if (fos != null) {
161+
try {
162+
fos.close();
163+
} catch (Exception e) {
164+
logger.error("CRITICAL: Failed to close FileOutputStream for uuid " + uuid + ": " + e.getMessage(), e);
165+
}
166+
}
151167

152168
// Calculate file size after writer is closed
153169
if (exportFilePath != null && exportStatus == EpipulseExportStatus.COMPLETED) {

0 commit comments

Comments
 (0)