From 2d515ad569e100abb09162488fd492ba0b0619eb Mon Sep 17 00:00:00 2001 From: Sabina Fataliyeva Date: Fri, 19 Jan 2024 09:26:02 +0200 Subject: [PATCH 1/2] Netex input summaries generation --- .../digitraffic/tis/vaco/db/RowMappers.java | 2 +- .../tis/vaco/packages/PackagesController.java | 2 +- .../tis/vaco/rules/internal/SummaryRule.java | 109 ------- .../vaco/summary/GtfsInputSummaryService.java | 29 +- .../summary/NetexInputSummaryService.java | 281 ++++++++++++++++++ .../tis/vaco/summary/SummaryRepository.java | 16 +- .../tis/vaco/summary/SummaryService.java | 15 +- .../tis/vaco/summary/model/netex/Line.java | 20 ++ .../model/netex/NetexInputSummary.java | 19 ++ .../tis/vaco/summary/model/netex/Route.java | 13 + .../tis/vaco/ui/model/summary/Card.java | 3 + .../vaco/ui/model/summary/LabelValuePair.java | 3 + 12 files changed, 376 insertions(+), 136 deletions(-) delete mode 100644 src/main/java/fi/digitraffic/tis/vaco/rules/internal/SummaryRule.java create mode 100644 src/main/java/fi/digitraffic/tis/vaco/summary/NetexInputSummaryService.java create mode 100644 src/main/java/fi/digitraffic/tis/vaco/summary/model/netex/Line.java create mode 100644 src/main/java/fi/digitraffic/tis/vaco/summary/model/netex/NetexInputSummary.java create mode 100644 src/main/java/fi/digitraffic/tis/vaco/summary/model/netex/Route.java diff --git a/src/main/java/fi/digitraffic/tis/vaco/db/RowMappers.java b/src/main/java/fi/digitraffic/tis/vaco/db/RowMappers.java index 8a465185..bb1e3a6a 100644 --- a/src/main/java/fi/digitraffic/tis/vaco/db/RowMappers.java +++ b/src/main/java/fi/digitraffic/tis/vaco/db/RowMappers.java @@ -160,7 +160,7 @@ private static RowMapper mapSummaryWithContent(ObjectMapper objectMappe FeedInfo feedInfo = objectMapper.readValue(rs.getBytes("raw"), new TypeReference<>() {}); content = EntryStateService.getFeedInfoUiContent(feedInfo); } - case "files", "counts", "components" -> content = objectMapper.readValue(rs.getBytes("raw"), new TypeReference<>() {}); + default -> content = objectMapper.readValue(rs.getBytes("raw"), new TypeReference<>() {}); } return ImmutableSummary.builder() .id(rs.getLong("id")) diff --git a/src/main/java/fi/digitraffic/tis/vaco/packages/PackagesController.java b/src/main/java/fi/digitraffic/tis/vaco/packages/PackagesController.java index 76fd8a72..79babe37 100644 --- a/src/main/java/fi/digitraffic/tis/vaco/packages/PackagesController.java +++ b/src/main/java/fi/digitraffic/tis/vaco/packages/PackagesController.java @@ -19,7 +19,7 @@ @RestController @RequestMapping("/packages") -@PreAuthorize("hasAuthority('vaco.apiuser')") +@PreAuthorize("hasAuthority('vaco.apiuser') and hasAuthority('vaco.user')") public class PackagesController { private final PackagesService packagesService; diff --git a/src/main/java/fi/digitraffic/tis/vaco/rules/internal/SummaryRule.java b/src/main/java/fi/digitraffic/tis/vaco/rules/internal/SummaryRule.java deleted file mode 100644 index 6ba13b73..00000000 --- a/src/main/java/fi/digitraffic/tis/vaco/rules/internal/SummaryRule.java +++ /dev/null @@ -1,109 +0,0 @@ -package fi.digitraffic.tis.vaco.rules.internal; - -import fi.digitraffic.tis.aws.s3.S3Path; -import fi.digitraffic.tis.utilities.model.ProcessingState; -import fi.digitraffic.tis.vaco.aws.S3Artifact; -import fi.digitraffic.tis.vaco.configuration.VacoProperties; -import fi.digitraffic.tis.vaco.packages.PackagesService; -import fi.digitraffic.tis.vaco.process.TaskService; -import fi.digitraffic.tis.vaco.process.model.Task; -import fi.digitraffic.tis.vaco.queuehandler.model.Entry; -import fi.digitraffic.tis.vaco.summary.GtfsInputSummaryService; -import fi.digitraffic.tis.vaco.rules.Rule; -import fi.digitraffic.tis.vaco.rules.model.ImmutableResultMessage; -import fi.digitraffic.tis.vaco.rules.model.ResultMessage; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Component; - -import java.nio.file.Path; -import java.util.HashMap; -import java.util.Objects; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; - -@Component -public class SummaryRule implements Rule { - private final Logger logger = LoggerFactory.getLogger(getClass()); - public static final String SUMMARY_TASK = "generate.summaries"; - private final TaskService taskService; - private final PackagesService packagesService; - private final GtfsInputSummaryService gtfsInputSummaryService; - - private final VacoProperties vacoProperties; - - public SummaryRule(TaskService taskService, - PackagesService packagesService, - GtfsInputSummaryService gtfsInputSummaryService, - VacoProperties vacoProperties) { - this.taskService = Objects.requireNonNull(taskService); - this.packagesService = Objects.requireNonNull(packagesService); - this.gtfsInputSummaryService = Objects.requireNonNull(gtfsInputSummaryService); - this.vacoProperties = Objects.requireNonNull(vacoProperties); - } - - @Override - public String getIdentifyingName() { - return SUMMARY_TASK; - } - - @Override - public CompletableFuture execute(Entry entry) { - return CompletableFuture.supplyAsync(() -> { - Optional task = taskService.findTask(entry.id(), SUMMARY_TASK); - - return task.map(t -> { - Task tracked = taskService.trackTask(entry, t, ProcessingState.START); - Optional downloadTask = taskService.findTask(entry.id(), DownloadRule.DOWNLOAD_SUBTASK); - if (downloadTask.isEmpty()) { - logger.error("Failed to generate task summaries due to entry's '{}' downloaded data task not existing in the db as a task", entry.id()); - return unsuccessfulResult(t, entry); - } - - Optional downloadedPackagePath = - packagesService.downloadPackage(entry, downloadTask.get(), "result"); - if (downloadedPackagePath.isEmpty()) { - logger.error("Failed to generate task summaries while trying to get S3 path to entry's '{}' downloaded data package", entry.id()); - return unsuccessfulResult(t, entry); - } - - taskService.trackTask(entry, t, ProcessingState.UPDATE); - try { - if ("gtfs".equalsIgnoreCase(entry.format())) { - gtfsInputSummaryService.generateGtfsDownloadSummaries(downloadedPackagePath.get(), t.id()); - } else if ("netex".equalsIgnoreCase(entry.format())) { - } - } catch (Exception e) { - return unsuccessfulResult(t, entry); - } - - S3Path ruleBasePath = S3Artifact.getRuleDirectory(entry.publicId(), - DownloadRule.DOWNLOAD_SUBTASK, DownloadRule.DOWNLOAD_SUBTASK); - S3Path ruleS3Input = ruleBasePath.resolve("input"); - - taskService.trackTask(entry, t, ProcessingState.COMPLETE); - - return ImmutableResultMessage.builder() - .entryId(entry.publicId()) - .taskId(tracked.id()) - .ruleName(SUMMARY_TASK) - .inputs(ruleS3Input.asUri(vacoProperties.s3ProcessingBucket())) - .outputs("") - .uploadedFiles(new HashMap<>()) - .build(); - }).orElseThrow(); - }); - } - - private ImmutableResultMessage unsuccessfulResult(Task t, Entry e) { - taskService.trackTask(e, t, ProcessingState.COMPLETE); - return ImmutableResultMessage.builder() - .entryId(e.publicId()) - .taskId(t.id()) - .ruleName(SUMMARY_TASK) - .inputs("") - .outputs("") - .uploadedFiles(new HashMap<>()) - .build(); - } -} diff --git a/src/main/java/fi/digitraffic/tis/vaco/summary/GtfsInputSummaryService.java b/src/main/java/fi/digitraffic/tis/vaco/summary/GtfsInputSummaryService.java index 7c75fccf..046795b2 100644 --- a/src/main/java/fi/digitraffic/tis/vaco/summary/GtfsInputSummaryService.java +++ b/src/main/java/fi/digitraffic/tis/vaco/summary/GtfsInputSummaryService.java @@ -1,12 +1,9 @@ package fi.digitraffic.tis.vaco.summary; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; import com.opencsv.CSVReader; import com.opencsv.bean.CsvToBeanBuilder; import com.opencsv.exceptions.CsvException; import fi.digitraffic.tis.utilities.Streams; -import fi.digitraffic.tis.vaco.summary.model.ImmutableSummary; import fi.digitraffic.tis.vaco.summary.model.RendererType; import fi.digitraffic.tis.vaco.summary.model.gtfs.Agency; import fi.digitraffic.tis.vaco.summary.model.gtfs.FeedInfo; @@ -36,14 +33,13 @@ public class GtfsInputSummaryService { private final Logger logger = LoggerFactory.getLogger(getClass()); private static final String COMPONENT_PRESENT_VALUE = "1"; private final SummaryRepository summaryRepository; - private final ObjectMapper objectMapper; - public GtfsInputSummaryService(SummaryRepository summaryRepository, ObjectMapper objectMapper) { + public GtfsInputSummaryService(SummaryRepository summaryRepository) { this.summaryRepository = summaryRepository; - this.objectMapper = objectMapper; } - public void generateGtfsDownloadSummaries(Path downloadedPackagePath, Long taskId) throws IOException { + public void generateGtfsInputSummaries(Path downloadedPackagePath, Long taskId) throws IOException { + logger.info("Starting GTFS input summary generation for task {}", taskId); ImmutableGtfsInputSummary gtfsTaskSummary = getEmptyGtfsSummaryObject(); try (ZipFile zipFile = new ZipFile(downloadedPackagePath.toFile())) { @@ -78,20 +74,11 @@ public void generateGtfsDownloadSummaries(Path downloadedPackagePath, Long taskI } } - persistTaskSummaryItem(taskId, "agencies", RendererType.CARD, gtfsTaskSummary.agencies()); - persistTaskSummaryItem(taskId, "feedInfo", RendererType.TABULAR, gtfsTaskSummary.feedInfo()); - persistTaskSummaryItem(taskId, "files", RendererType.LIST, gtfsTaskSummary.files()); - persistTaskSummaryItem(taskId, "counts", RendererType.LIST, gtfsTaskSummary.counts()); - persistTaskSummaryItem(taskId, "components", RendererType.LIST, gtfsTaskSummary.components()); - } - - void persistTaskSummaryItem(Long taskId, String itemName, RendererType rendererType, T data) { - try { - summaryRepository.create(ImmutableSummary.of(taskId, itemName, rendererType, objectMapper.writeValueAsBytes(data))); - } - catch (JsonProcessingException e) { - logger.error("Failed to persist {}'s summary data {} generated for task {}", itemName, data, taskId, e); - } + summaryRepository.persistTaskSummaryItem(taskId, "agencies", RendererType.CARD, gtfsTaskSummary.agencies()); + summaryRepository.persistTaskSummaryItem(taskId, "feedInfo", RendererType.TABULAR, gtfsTaskSummary.feedInfo()); + summaryRepository.persistTaskSummaryItem(taskId, "files", RendererType.LIST, gtfsTaskSummary.files()); + summaryRepository.persistTaskSummaryItem(taskId, "counts", RendererType.LIST, gtfsTaskSummary.counts()); + summaryRepository.persistTaskSummaryItem(taskId, "components", RendererType.LIST, gtfsTaskSummary.components()); } ImmutableGtfsInputSummary getEmptyGtfsSummaryObject() { diff --git a/src/main/java/fi/digitraffic/tis/vaco/summary/NetexInputSummaryService.java b/src/main/java/fi/digitraffic/tis/vaco/summary/NetexInputSummaryService.java new file mode 100644 index 00000000..cd7ce839 --- /dev/null +++ b/src/main/java/fi/digitraffic/tis/vaco/summary/NetexInputSummaryService.java @@ -0,0 +1,281 @@ +package fi.digitraffic.tis.vaco.summary; + +import fi.digitraffic.tis.vaco.summary.model.RendererType; +import fi.digitraffic.tis.vaco.summary.model.netex.ImmutableLine; +import fi.digitraffic.tis.vaco.summary.model.netex.ImmutableNetexInputSummary; +import fi.digitraffic.tis.vaco.summary.model.netex.ImmutableRoute; +import fi.digitraffic.tis.vaco.summary.model.netex.Line; +import fi.digitraffic.tis.vaco.summary.model.netex.NetexInputSummary; +import fi.digitraffic.tis.vaco.summary.model.netex.Route; +import fi.digitraffic.tis.vaco.ui.model.summary.Card; +import fi.digitraffic.tis.vaco.ui.model.summary.ImmutableCard; +import fi.digitraffic.tis.vaco.ui.model.summary.ImmutableLabelValuePair; +import fi.digitraffic.tis.vaco.ui.model.summary.LabelValuePair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +import javax.xml.namespace.QName; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.Attribute; +import javax.xml.stream.events.EndElement; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +@Service +public class NetexInputSummaryService { + private final Logger logger = LoggerFactory.getLogger(getClass()); + private final SummaryRepository summaryRepository; + + public NetexInputSummaryService(SummaryRepository summaryRepository) { + this.summaryRepository = summaryRepository; + } + + public void generateNetexInputSummaries(Path downloadedPackagePath, Long taskId) throws IOException { + logger.info("Starting NeTEx input summary generation for task {}", taskId); + ImmutableNetexInputSummary.Builder netexInputSummaryBuilder = getEmptyNetexSummaryBuilder(); + int operatorTotalCount = 0; + int routeTotalCount = 0; + int lineTotalCount = 0; + int stopPlaceTotalCount = 0; + int quayTotalCount = 0; + int journeyPatternTotalCount = 0; + int serviceJourneysTotalCount = 0; + + try (ZipFile zipFile = new ZipFile(downloadedPackagePath.toFile())) { + Enumeration entries = zipFile.entries(); + while (entries.hasMoreElements()) { + ZipEntry zipEntry = entries.nextElement(); + if (!zipEntry.isDirectory()) { + netexInputSummaryBuilder.addFiles(zipEntry.getName()); + if (!zipEntry.getName().endsWith(".xml")) { + continue; + } + try (InputStream inputStream = zipFile.getInputStream(zipEntry)) { + XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance(); + XMLEventReader reader = xmlInputFactory.createXMLEventReader(inputStream); + List lines = new ArrayList<>(); + List routes = new ArrayList<>(); + + while (reader.hasNext()) { + try { + XMLEvent nextEvent = reader.nextEvent(); + if (nextEvent.isStartElement()) { + StartElement startElement = nextEvent.asStartElement(); + switch (startElement.getName().getLocalPart()) { + case "Operator" -> { + operatorTotalCount++; + processOperator(reader, startElement, + netexInputSummaryBuilder, zipEntry.getName(), taskId); + } + case "Route" -> { + routeTotalCount++; + Route route = processRoute(reader, startElement, zipEntry.getName(), taskId); + if (route.lineRef() != null) { + routes.add(route); + } + } + case "Line" -> { + lineTotalCount++; + lines.add(processLine(reader, startElement, zipEntry.getName(), taskId)); + } + case "StopPlace" -> stopPlaceTotalCount++; + case "Quay" -> quayTotalCount++; + case "JourneyPattern" -> journeyPatternTotalCount++; + case "ServiceJourney" -> serviceJourneysTotalCount++; + } + } + } catch (Exception e) { + logger.error("Failure while processing file {} for task {}", zipEntry.getName(), taskId, e); + } + } + produceLineSummaries(netexInputSummaryBuilder, lines, routes); + } catch (XMLStreamException e) { + logger.error("Failure to initiate xmlInputFactory while processing file {} for task {}", + zipEntry.getName(), taskId, e); + } + } + } + } + + List counts = List.of( + "Operators: " + operatorTotalCount, + "Lines: " + lineTotalCount, + "Routes: " + routeTotalCount, + "Stop places: " + stopPlaceTotalCount, + "Quays: " + quayTotalCount, + "Journey patterns: " + journeyPatternTotalCount, + "Service journeys: " + serviceJourneysTotalCount); + + netexInputSummaryBuilder.counts(counts); + NetexInputSummary netexInputSummary = netexInputSummaryBuilder.build(); + summaryRepository.persistTaskSummaryItem(taskId, "operators", RendererType.CARD, netexInputSummary.operators()); + summaryRepository.persistTaskSummaryItem(taskId, "lines", RendererType.CARD, netexInputSummary.lines()); + summaryRepository.persistTaskSummaryItem(taskId, "files", RendererType.LIST, netexInputSummary.files()); + summaryRepository.persistTaskSummaryItem(taskId, "counts", RendererType.LIST, netexInputSummary.counts()); + } + + void processOperator(XMLEventReader reader, + StartElement operatorStartElement, + ImmutableNetexInputSummary.Builder netexInputSummaryBuilder, + String fileName, + Long taskId) { + ImmutableCard.Builder cardBuilder = ImmutableCard.builder(); + List cardContent = new ArrayList<>(); + + Attribute id = operatorStartElement.getAttributeByName(new QName("id")); + if (id != null) { + cardContent.add(ImmutableLabelValuePair.of("id", id.getValue())); + } + + while (reader.hasNext()) { + try { + XMLEvent nextEvent = reader.nextEvent(); + if (nextEvent.isStartElement()) { + StartElement startElement = nextEvent.asStartElement(); + switch (startElement.getName().getLocalPart()) { + case "Name" -> { + nextEvent = reader.nextEvent(); + String name = nextEvent.asCharacters().getData(); + cardBuilder.title(name); + } + case "Email" -> { + nextEvent = reader.nextEvent(); + String email = nextEvent.asCharacters().getData(); + cardContent.add(ImmutableLabelValuePair.of("email", email)); + } + case "Url" -> { + nextEvent = reader.nextEvent(); + String url = nextEvent.asCharacters().getData(); + cardContent.add(ImmutableLabelValuePair.of("website", url)); + } + case "Phone" -> { + nextEvent = reader.nextEvent(); + String phone = nextEvent.asCharacters().getData(); + cardContent.add(ImmutableLabelValuePair.of("phone", phone)); + } + } + } + if (nextEvent.isEndElement()) { + EndElement endElement = nextEvent.asEndElement(); + if (endElement.getName().getLocalPart().equals("Operator")) { + break; + } + } + } catch (Exception e) { + logger.error("Failed to process operator in {} as part of task {}", fileName, taskId, e); + } + } + + Card operator = cardBuilder.content(cardContent).build(); + netexInputSummaryBuilder.addOperators(operator); + } + + Route processRoute(XMLEventReader reader, + StartElement routeStartElement, + String fileName, + Long taskId) { + ImmutableRoute.Builder routeBuilder = ImmutableRoute.builder(); + Attribute id = routeStartElement.getAttributeByName(new QName("id")); + if (id != null) { + routeBuilder.id(id.getValue()); + } + + while (reader.hasNext()) { + try { + XMLEvent nextEvent = reader.nextEvent(); + if (nextEvent.isStartElement()) { + StartElement startElement = nextEvent.asStartElement(); + if ("LineRef".equals(startElement.getName().getLocalPart())) { + Attribute lineRef = startElement.getAttributeByName(new QName("ref")); + if (lineRef != null) { + routeBuilder.lineRef(lineRef.getValue()); + } + break; + } + } + } catch (Exception e) { + logger.error("Failed to process route in {} as part of task {}", fileName, taskId, e); + } + } + + return routeBuilder.build(); + } + + Line processLine(XMLEventReader reader, + StartElement lineStartElement, + String fileName, + Long taskId) { + ImmutableLine.Builder lineBuilder = ImmutableLine.builder(); + Attribute id = lineStartElement.getAttributeByName(new QName("id")); + if (id != null) { + lineBuilder.id(id.getValue()); + } + + while (reader.hasNext()) { + try { + XMLEvent nextEvent = reader.nextEvent(); + if (nextEvent.isStartElement()) { + StartElement startElement = nextEvent.asStartElement(); + switch (startElement.getName().getLocalPart()) { + case "Name" -> { + nextEvent = reader.nextEvent(); + lineBuilder.name(nextEvent.asCharacters().getData()); + } + case "TransportMode" -> { + nextEvent = reader.nextEvent(); + lineBuilder.transportMode(nextEvent.asCharacters().getData()); + } + } + } + if (nextEvent.isEndElement()) { + EndElement endElement = nextEvent.asEndElement(); + if (endElement.getName().getLocalPart().equals("Line")) { + break; + } + } + } catch (Exception e) { + logger.error("Failed to process line in {} as part of task {}", fileName, taskId, e); + } + } + + return lineBuilder.build(); + } + + void produceLineSummaries(ImmutableNetexInputSummary.Builder netexInputSummaryBuilder, + List lines, List routes) { + List lineCards = new ArrayList<>(); + + lines.forEach(line -> { + int routeCount = routes.stream().filter(route -> route.lineRef().equals(line.id())).toList().size(); + List cardContent = List.of( + ImmutableLabelValuePair.of("transportMode", line.transportMode()), + ImmutableLabelValuePair.of("routesCount", String.valueOf(routeCount))); + lineCards.add(ImmutableCard.builder() + .title(line.name()) + .content(cardContent) + .build()); + }); + + netexInputSummaryBuilder.addAllLines(lineCards); + } + + ImmutableNetexInputSummary.Builder getEmptyNetexSummaryBuilder() { + return ImmutableNetexInputSummary.builder() + .operators(Collections.emptyList()) + .lines(Collections.emptyList()) + .files(Collections.emptyList()) + .counts(Collections.emptyList()); + } +} diff --git a/src/main/java/fi/digitraffic/tis/vaco/summary/SummaryRepository.java b/src/main/java/fi/digitraffic/tis/vaco/summary/SummaryRepository.java index ff424258..3a6de2fa 100644 --- a/src/main/java/fi/digitraffic/tis/vaco/summary/SummaryRepository.java +++ b/src/main/java/fi/digitraffic/tis/vaco/summary/SummaryRepository.java @@ -1,8 +1,13 @@ package fi.digitraffic.tis.vaco.summary; +import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import fi.digitraffic.tis.vaco.db.RowMappers; +import fi.digitraffic.tis.vaco.summary.model.ImmutableSummary; +import fi.digitraffic.tis.vaco.summary.model.RendererType; import fi.digitraffic.tis.vaco.summary.model.Summary; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; @@ -11,7 +16,7 @@ @Repository public class SummaryRepository { - + private final Logger logger = LoggerFactory.getLogger(getClass()); private final JdbcTemplate jdbc; private final ObjectMapper objectMapper; @@ -20,6 +25,15 @@ public SummaryRepository(JdbcTemplate jdbc, ObjectMapper objectMapper) { this.objectMapper = objectMapper; } + void persistTaskSummaryItem(Long taskId, String itemName, RendererType rendererType, T data) { + try { + create(ImmutableSummary.of(taskId, itemName, rendererType, objectMapper.writeValueAsBytes(data))); + } + catch (JsonProcessingException e) { + logger.error("Failed to persist {}'s summary data {} generated for task {}", itemName, data, taskId, e); + } + } + public Summary create(Summary summary) { return jdbc.queryForObject(""" INSERT INTO summary (task_id, name, renderer_type, raw) diff --git a/src/main/java/fi/digitraffic/tis/vaco/summary/SummaryService.java b/src/main/java/fi/digitraffic/tis/vaco/summary/SummaryService.java index e3b6088f..7bdf9ec9 100644 --- a/src/main/java/fi/digitraffic/tis/vaco/summary/SummaryService.java +++ b/src/main/java/fi/digitraffic/tis/vaco/summary/SummaryService.java @@ -19,10 +19,14 @@ public class SummaryService { private final Logger logger = LoggerFactory.getLogger(getClass()); private final PackagesService packagesService; private final GtfsInputSummaryService gtfsInputSummaryService; + private final NetexInputSummaryService netexInputSummaryService; - public SummaryService(PackagesService packagesService, GtfsInputSummaryService gtfsInputSummaryService) { + public SummaryService(PackagesService packagesService, + GtfsInputSummaryService gtfsInputSummaryService, + NetexInputSummaryService netexInputSummaryService) { this.packagesService = packagesService; this.gtfsInputSummaryService = gtfsInputSummaryService; + this.netexInputSummaryService = netexInputSummaryService; } public void generateSummaries(Entry entry, Task task) { @@ -40,11 +44,16 @@ private void generateInputDataSummaries(Entry entry, Task task) { if (TransitDataFormat.GTFS.fieldName().equals(entry.format())) { try { - gtfsInputSummaryService.generateGtfsDownloadSummaries(downloadedPackagePath.get(), task.id()); + gtfsInputSummaryService.generateGtfsInputSummaries(downloadedPackagePath.get(), task.id()); } catch (IOException e) { - logger.error("Failed to generate input data summaries for entry {}", entry.id(), e); + logger.error("Failed to generate GTFS input data summaries for entry {}", entry.id(), e); } } else if (TransitDataFormat.NETEX.fieldName().equals(entry.format())) { + try { + netexInputSummaryService.generateNetexInputSummaries(downloadedPackagePath.get(), task.id()); + } catch (IOException e) { + logger.error("Failed to generate NeTEx input data summaries for entry {}", entry.id(), e); + } } } } diff --git a/src/main/java/fi/digitraffic/tis/vaco/summary/model/netex/Line.java b/src/main/java/fi/digitraffic/tis/vaco/summary/model/netex/Line.java new file mode 100644 index 00000000..5999b0cf --- /dev/null +++ b/src/main/java/fi/digitraffic/tis/vaco/summary/model/netex/Line.java @@ -0,0 +1,20 @@ +package fi.digitraffic.tis.vaco.summary.model.netex; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import jakarta.annotation.Nullable; +import org.immutables.value.Value; + +@Value.Immutable +@JsonSerialize(as = ImmutableLine.class) +@JsonDeserialize(as = ImmutableLine.class) +public interface Line { + String id(); + String name(); + @Nullable + String transportMode(); + @Nullable + String validityStartDate(); + @Nullable + String validityEndDate(); +} diff --git a/src/main/java/fi/digitraffic/tis/vaco/summary/model/netex/NetexInputSummary.java b/src/main/java/fi/digitraffic/tis/vaco/summary/model/netex/NetexInputSummary.java new file mode 100644 index 00000000..13e77c54 --- /dev/null +++ b/src/main/java/fi/digitraffic/tis/vaco/summary/model/netex/NetexInputSummary.java @@ -0,0 +1,19 @@ +package fi.digitraffic.tis.vaco.summary.model.netex; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import fi.digitraffic.tis.vaco.ui.model.summary.Card; +import org.immutables.value.Value; + +import java.util.List; + +@Value.Immutable +@JsonSerialize(as = ImmutableNetexInputSummary.class) +@JsonDeserialize(as = ImmutableNetexInputSummary.class) +@Value.Style(jdk9Collections = true) +public interface NetexInputSummary { + List operators(); + List lines(); + List files(); + List counts(); +} diff --git a/src/main/java/fi/digitraffic/tis/vaco/summary/model/netex/Route.java b/src/main/java/fi/digitraffic/tis/vaco/summary/model/netex/Route.java new file mode 100644 index 00000000..a0e58d4c --- /dev/null +++ b/src/main/java/fi/digitraffic/tis/vaco/summary/model/netex/Route.java @@ -0,0 +1,13 @@ +package fi.digitraffic.tis.vaco.summary.model.netex; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import org.immutables.value.Value; + +@Value.Immutable +@JsonSerialize(as = ImmutableRoute.class) +@JsonDeserialize(as = ImmutableRoute.class) +public interface Route { + String id(); + String lineRef(); +} diff --git a/src/main/java/fi/digitraffic/tis/vaco/ui/model/summary/Card.java b/src/main/java/fi/digitraffic/tis/vaco/ui/model/summary/Card.java index e886c3a1..38d5d537 100644 --- a/src/main/java/fi/digitraffic/tis/vaco/ui/model/summary/Card.java +++ b/src/main/java/fi/digitraffic/tis/vaco/ui/model/summary/Card.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import jakarta.validation.constraints.NotNull; import org.immutables.value.Value; @Value.Immutable @@ -9,5 +10,7 @@ @JsonDeserialize(as = ImmutableCard.class) public interface Card { String title(); + + @NotNull Object content(); } diff --git a/src/main/java/fi/digitraffic/tis/vaco/ui/model/summary/LabelValuePair.java b/src/main/java/fi/digitraffic/tis/vaco/ui/model/summary/LabelValuePair.java index f4ecbd87..805c3d15 100644 --- a/src/main/java/fi/digitraffic/tis/vaco/ui/model/summary/LabelValuePair.java +++ b/src/main/java/fi/digitraffic/tis/vaco/ui/model/summary/LabelValuePair.java @@ -9,8 +9,11 @@ @JsonSerialize(as = ImmutableLabelValuePair.class) @JsonDeserialize(as = ImmutableLabelValuePair.class) public interface LabelValuePair { + @Value.Parameter @Nullable String label(); + + @Value.Parameter @Nullable String value(); } From db92494747ff4ec5299b6d9ab5729cc6bf127c89 Mon Sep 17 00:00:00 2001 From: Sabina Fataliyeva Date: Fri, 19 Jan 2024 09:48:58 +0200 Subject: [PATCH 2/2] Order summary columns in a steady custom way --- .../tis/vaco/summary/SummaryRepository.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/java/fi/digitraffic/tis/vaco/summary/SummaryRepository.java b/src/main/java/fi/digitraffic/tis/vaco/summary/SummaryRepository.java index 3a6de2fa..ed448bd6 100644 --- a/src/main/java/fi/digitraffic/tis/vaco/summary/SummaryRepository.java +++ b/src/main/java/fi/digitraffic/tis/vaco/summary/SummaryRepository.java @@ -67,6 +67,16 @@ public List findTaskSummaryByEntryId(Long entryId) { FROM summary ts JOIN task t ON ts.task_id = t.id WHERE t.entry_id = ? + ORDER BY CASE + WHEN ts.name = 'agencies' THEN 1 + WHEN ts.name = 'operators' THEN 1 + WHEN ts.name = 'feedInfo' THEN 2 + WHEN ts.name = 'lines' THEN 2 + WHEN ts.name = 'files' THEN 3 + WHEN ts.name = 'counts' THEN 4 + WHEN ts.name = 'components' THEN 5 + ELSE 6 + END ASC """, RowMappers.SUMMARY_WITH_CONTENT.apply(objectMapper), entryId);