Skip to content

Commit

Permalink
feat: relatedTrainInformationRequest (#216) (#468)
Browse files Browse the repository at this point in the history
  • Loading branch information
mghilardelli authored Dec 17, 2024
1 parent 22b31ad commit 50bedbb
Show file tree
Hide file tree
Showing 8 changed files with 105 additions and 24 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package ch.sbb.sferamock.messages.services;

import ch.sbb.sferamock.adapters.sfera.model.v0201.G2BEventPayload;
import ch.sbb.sferamock.adapters.sfera.model.v0201.RelatedTrainInformation;
import ch.sbb.sferamock.messages.common.XmlHelper;
import ch.sbb.sferamock.messages.model.TrainIdentification;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
Expand All @@ -10,6 +12,8 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.springframework.boot.ApplicationArguments;
Expand All @@ -31,6 +35,36 @@ public EventRepository(XmlHelper xmlHelper) {
this.xmlHelper = xmlHelper;
}

private static String extractOperationalNumber(String filename) {
Pattern pattern = Pattern.compile(XML_REGEX);
Matcher matcher = pattern.matcher(filename);
if (matcher.find()) {
String directoryOperationalNumber = matcher.group(1);
String fileOperationalNumber = matcher.group(2);
if (directoryOperationalNumber != null && directoryOperationalNumber.equals(fileOperationalNumber)) {
return directoryOperationalNumber;
}
}
throw new RuntimeException("Operational number extraction in Event repository failed for file: " + filename);
}

private static int extractOffsetMs(String filename) {
Pattern pattern = Pattern.compile(OFFSET_XML_REGEX);
Matcher matcher = pattern.matcher(filename);
if (matcher.find()) {
return Integer.parseInt(matcher.group(1));
}
throw new RuntimeException("Offset extraction in Event repository failed for file: " + filename);
}

public Optional<RelatedTrainInformation> getRelatedTrainInformation(TrainIdentification trainIdentification) {
return Optional.ofNullable(events.get(trainIdentification.operationalNumber()))
.flatMap(trainEvents -> trainEvents.stream()
.map(event -> event.payload.getRelatedTrainInformation())
.filter(Objects::nonNull)
.findFirst());
}

@Override
public void run(ApplicationArguments args) throws Exception {
importEvents();
Expand All @@ -57,28 +91,6 @@ private void importEvents() throws IOException {
}
}

private static String extractOperationalNumber(String filename) {
Pattern pattern = Pattern.compile(XML_REGEX);
Matcher matcher = pattern.matcher(filename);
if (matcher.find()) {
String directoryOperationalNumber = matcher.group(1);
String fileOperationalNumber = matcher.group(2);
if (directoryOperationalNumber != null && directoryOperationalNumber.equals(fileOperationalNumber)) {
return directoryOperationalNumber;
}
}
throw new RuntimeException("Operational number extraction in Event repository failed for file: " + filename);
}

private static int extractOffsetMs(String filename) {
Pattern pattern = Pattern.compile(OFFSET_XML_REGEX);
Matcher matcher = pattern.matcher(filename);
if (matcher.find()) {
return Integer.parseInt(matcher.group(1));
}
throw new RuntimeException("Offset extraction in Event repository failed for file: " + filename);
}

public record Event(int offsetMs, G2BEventPayload payload) {

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public void run(ApplicationArguments args) throws Exception {
importJps();
}

// company and startDate is ignored
public Optional<JourneyProfile> getJourneyProfile(TrainIdentification trainIdentification) {
return Optional.ofNullable(journeyProfiles.get(trainIdentification.operationalNumber()));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public void run(ApplicationArguments args) throws Exception {
importSps();
}

// segment version and company is ignored
public Optional<SegmentProfile> getSegmentProfile(SegmentIdentification spId) {
return Optional.ofNullable(segmentProfiles.get(spId.id()));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package ch.sbb.sferamock.messages.services;

import ch.sbb.sferamock.adapters.sfera.model.v0201.JourneyProfile;
import ch.sbb.sferamock.adapters.sfera.model.v0201.RelatedTrainInformation;
import ch.sbb.sferamock.adapters.sfera.model.v0201.SPZoneComplexType;
import ch.sbb.sferamock.adapters.sfera.model.v0201.SegmentProfile;
import ch.sbb.sferamock.adapters.sfera.model.v0201.TrainCharacteristics;
Expand Down Expand Up @@ -31,17 +32,19 @@ public class SferaApplicationService {
private final JourneyProfileRepository journeyProfileRepository;
private final SegmentProfileRepository segmentProfileRepository;
private final TrainCharacteristicsRepository trainCharacteristicsRepository;
private final EventRepository eventRepository;

public SferaApplicationService(ReplyPublisher replyPublisher, RequestContextRepository requestContextRepository, OperationModeSelector operationModeSelector,
RegistrationService registrationService, JourneyProfileRepository journeyProfileRepository, SegmentProfileRepository segmentProfileRepository,
TrainCharacteristicsRepository trainCharacteristicsRepository) {
TrainCharacteristicsRepository trainCharacteristicsRepository, EventRepository eventRepository) {
this.replyPublisher = replyPublisher;
this.requestContextRepository = requestContextRepository;
this.operationModeSelector = operationModeSelector;
this.registrationService = registrationService;
this.journeyProfileRepository = journeyProfileRepository;
this.segmentProfileRepository = segmentProfileRepository;
this.trainCharacteristicsRepository = trainCharacteristicsRepository;
this.eventRepository = eventRepository;
}

private static JourneyProfile unavailableJourneyProfile() {
Expand Down Expand Up @@ -130,6 +133,23 @@ public void processTrainCharacteristicsRequest(List<TrainCharacteristicsIdentifi
publishTrainCharacteristics(trainCharacteristics, correlationId, requestContext);
}

public void processRelatedTrainInformationRequest(List<TrainIdentification> trainIdentifications, RequestContext requestContext) {
if (!registrationService.isRegistered(requestContext.clientId())) {
publishErrorMessageUnregisteredClient(requestContext);
return;
}

var correlationId = UUID.randomUUID();
requestContextRepository.storeRequestContext(correlationId, requestContext);

List<RelatedTrainInformation> relatedTrainInformations = trainIdentifications.stream().map(trainIdentification ->
eventRepository.getRelatedTrainInformation(trainIdentification).orElse(null))
.filter(Objects::nonNull)
.toList();

publishRelatedTrainInformations(relatedTrainInformations, correlationId, requestContext);
}

private void publishJourneyProfile(Optional<JourneyProfile> journeyProfile, UUID correlationId, RequestContext requestContext) {
requestContextRepository.getRequestContext(correlationId)
.ifPresentOrElse(it -> publishJourneyProfileResponse(journeyProfile, it), () -> replyPublisher.publishErrorMessage(SferaErrorCodes.COULD_NOT_PROCESS_DATA, requestContext));
Expand Down Expand Up @@ -166,6 +186,20 @@ private void publishTrainCharacteristicsResponse(List<TrainCharacteristics> trai
}
}

private void publishRelatedTrainInformations(List<RelatedTrainInformation> relatedTrainInformations, UUID correlationId, RequestContext requestContext) {
requestContextRepository.getRequestContext(correlationId)
.ifPresentOrElse(it -> publishRelatedTrainInformationsResponse(relatedTrainInformations, it),
() -> replyPublisher.publishErrorMessage(SferaErrorCodes.COULD_NOT_PROCESS_DATA, requestContext));
}

private void publishRelatedTrainInformationsResponse(List<RelatedTrainInformation> relatedTrainInformations, RequestContext requestContext) {
if (!relatedTrainInformations.isEmpty()) {
replyPublisher.publishRelatedTrainInformations(relatedTrainInformations, requestContext);
} else {
replyPublisher.publishErrorMessage(SferaErrorCodes.COULD_NOT_PROCESS_DATA, requestContext);
}
}

private void publishOk(RequestContext requestContext) {
replyPublisher.publishOkMessage(requestContext);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import ch.sbb.sferamock.adapters.sfera.model.v0201.B2GRequest;
import ch.sbb.sferamock.adapters.sfera.model.v0201.JPRequest;
import ch.sbb.sferamock.adapters.sfera.model.v0201.RelatedTrainInformationRequest;
import ch.sbb.sferamock.adapters.sfera.model.v0201.SFERAB2GEventMessage;
import ch.sbb.sferamock.adapters.sfera.model.v0201.SFERAB2GReplyMessage;
import ch.sbb.sferamock.adapters.sfera.model.v0201.SFERAB2GRequestMessage;
Expand Down Expand Up @@ -113,6 +114,10 @@ private void processB2GRequest(SFERAB2GRequestMessage request, String topic) {
processTrainCharacteristicsRequest(b2GRequest.getTCRequest(), requestContext);
return;
}
if (b2GRequest != null && b2GRequest.getRelatedTrainInformationRequest() != null && !b2GRequest.getRelatedTrainInformationRequest().isEmpty()) {
processRelatedTrainInformationRequest(b2GRequest.getRelatedTrainInformationRequest(), requestContext);
return;
}
log.warn("A B2G Request that is not a handshake should currently have exactly one jp or sp request. Request is ignored.");
}
}
Expand Down Expand Up @@ -163,4 +168,12 @@ private void processTrainCharacteristicsRequest(List<TCRequest> tcRequests, Requ
new CompanyCode(tcRequest.getTCRUID()))).toList();
sferaApplicationService.processTrainCharacteristicsRequest(trainCharacteristicsIdentifications, requestContext);
}

private void processRelatedTrainInformationRequest(List<RelatedTrainInformationRequest> relatedTrainInformationRequests, RequestContext requestContext) {
var trainIdentifications = relatedTrainInformationRequests.stream()
.map(relatedTrainInformationRequest -> relatedTrainInformationRequest.getTrainIdentification().getOTNID())
.map(otnId -> new TrainIdentification(new CompanyCode(otnId.getCompany()), otnId.getOperationalTrainNumber(), XmlDateHelper.toLocalDate(otnId.getStartDate())))
.toList();
sferaApplicationService.processRelatedTrainInformationRequest(trainIdentifications, requestContext);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static org.springframework.util.MimeTypeUtils.APPLICATION_XML;

import ch.sbb.sferamock.adapters.sfera.model.v0201.JourneyProfile;
import ch.sbb.sferamock.adapters.sfera.model.v0201.RelatedTrainInformation;
import ch.sbb.sferamock.adapters.sfera.model.v0201.SFERAG2BReplyMessage;
import ch.sbb.sferamock.adapters.sfera.model.v0201.SegmentProfile;
import ch.sbb.sferamock.adapters.sfera.model.v0201.TrainCharacteristics;
Expand Down Expand Up @@ -55,6 +56,12 @@ public void publishTrainCharacteristics(List<TrainCharacteristics> trainCharacte
publishReplyMessage(reply, requestContext);
}

public void publishRelatedTrainInformations(List<RelatedTrainInformation> relatedTrainInformations, RequestContext requestContext) {
var header = sferaMessageCreator.createMessageHeader(UUID.randomUUID(), requestContext.tid(), requestContext.incomingMessageId());
var reply = sferaMessageCreator.createRelatedTrainInformationReplyMessage(relatedTrainInformations, header);
publishReplyMessage(reply, requestContext);
}

public void publishHandshakeAcknowledge(OperationMode.Connectivity connectivity,
OperationMode.Architecture architecture,
RequestContext requestContext) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import ch.sbb.sferamock.adapters.sfera.model.v0201.MessageHeader;
import ch.sbb.sferamock.adapters.sfera.model.v0201.OTNIDComplexType;
import ch.sbb.sferamock.adapters.sfera.model.v0201.Recipient;
import ch.sbb.sferamock.adapters.sfera.model.v0201.RelatedTrainInformation;
import ch.sbb.sferamock.adapters.sfera.model.v0201.SFERAG2BEventMessage;
import ch.sbb.sferamock.adapters.sfera.model.v0201.SFERAG2BReplyMessage;
import ch.sbb.sferamock.adapters.sfera.model.v0201.SegmentProfile;
Expand Down Expand Up @@ -195,6 +196,16 @@ public SFERAG2BReplyMessage createTrainCharacteristicsReplyMessage(List<TrainCha
return result;
}

public SFERAG2BReplyMessage createRelatedTrainInformationReplyMessage(List<RelatedTrainInformation> relatedTrainInformations, MessageHeader header) {
var result = new SFERAG2BReplyMessage();
result.setMessageHeader(header);
var payload = new G2BReplyPayload();
relatedTrainInformations.forEach(relatedTrainInformation -> relatedTrainInformation.getOwnTrain().setTrainIdentification(header.getTrainIdentification()));
payload.getRelatedTrainInformation().addAll(relatedTrainInformations);
result.setG2BReplyPayload(payload);
return result;
}

public SFERAG2BReplyMessage createOkMessage(MessageHeader header) {
var result = new SFERAG2BReplyMessage();
result.setMessageHeader(header);
Expand Down
4 changes: 3 additions & 1 deletion webapp/src/app/sfera-observer/sfera-observer.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,13 +141,15 @@ export class SferaObserverComponent implements OnDestroy {
return this.getSegmentProfiles(document);
} else if (this.containsElement(document, 'TrainCharacteristics')) {
return this.getTrainCharacteristics(document);
} else if (this.containsElement(document, 'RelatedTrainInformation')) {
return 'RelatedTrainInformation';
}
} else if (type == "SFERA_B2G_RequestMessage") {
if (this.isHandshakeRequest(document)) {
return `HS-REQUEST`;
}

const requestTypes = ['JP_Request', 'SP_Request', 'TC_Request']
const requestTypes = ['JP_Request', 'SP_Request', 'TC_Request', 'RelatedTrainInformationRequest']
const requestedTypes: string[] = [];

for (const requestType of requestTypes) {
Expand Down

0 comments on commit 50bedbb

Please sign in to comment.