Skip to content

Commit

Permalink
refactor and add event service that merges query results
Browse files Browse the repository at this point in the history
  • Loading branch information
Battlestad committed Oct 1, 2024
1 parent 3f582a1 commit 47009a1
Show file tree
Hide file tree
Showing 6 changed files with 276 additions and 87 deletions.
180 changes: 180 additions & 0 deletions src/main/java/no/fintlabs/EventService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
package no.fintlabs;

import lombok.AllArgsConstructor;
import no.fintlabs.model.*;
import no.fintlabs.repositories.EventRepository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import java.time.OffsetDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@AllArgsConstructor
public class EventService {

private final EventRepository eventRepository;

public void save(Event event) {
eventRepository.save(event);
}

public Page<EventDto> findAll(Pageable pageable) {
return convertPageOfEventIntoPageOfEventDto(eventRepository.findAll(pageable));
}

public Page<EventDto> getMergedLatestEvents(Pageable pageable) {
List<Event> latestEvents = eventRepository
.findLatestEventPerSourceApplicationInstanceId(pageable).getContent();

List<Event> latestNonDeletedEvents = eventRepository
.findLatestEventNotDeletedPerSourceApplicationInstanceId(pageable).getContent();

return getEventDtos(pageable, latestNonDeletedEvents, latestEvents);
}

public Page<EventDto> getMergedLatestEventsWhereSourceApplicationIdIn(
List<Long> sourceApplicationIds,
Pageable pageable
) {
List<Event> latestEvents = eventRepository
.findLatestEventPerSourceApplicationInstanceIdAndSourceApplicationIdIn(
sourceApplicationIds,
pageable
).getContent();

List<Event> latestNonDeletedEvents = eventRepository
.findLatestEventNotDeletedPerSourceApplicationInstanceIdAndSourceApplicationIdIn(
sourceApplicationIds,
pageable
).getContent();

return getEventDtos(pageable, latestNonDeletedEvents, latestEvents);
}

private PageImpl<EventDto> getEventDtos(Pageable pageable, List<Event> latestNonDeletedEvents, List<Event> latestEvents) {
Map<String, Event> nonDeletedEventMap = latestNonDeletedEvents.stream()
.collect(
Collectors.toMap(
event -> event.getInstanceFlowHeaders().getSourceApplicationInstanceId(),
event -> event
)
);

List<EventDto> mergedEvents = new ArrayList<>();

for (Event latestEvent : latestEvents) {
if ("instance-deleted".equals(latestEvent.getName())) {
Event nonDeletedEvent = nonDeletedEventMap
.get(latestEvent.getInstanceFlowHeaders().getSourceApplicationInstanceId());
if (nonDeletedEvent != null) {
EventDto updatedEventDto = EventToEventDto(nonDeletedEvent);
updatedEventDto.setStatus("deleted");
mergedEvents.add(updatedEventDto);
}
} else {
EventDto eventDto = EventToEventDto(latestEvent);
mergedEvents.add(eventDto);
}
}

int start = (int) pageable.getOffset();
int end = Math.min((start + pageable.getPageSize()), mergedEvents.size());

List<EventDto> paginatedList = mergedEvents.subList(start, end);

return new PageImpl<>(paginatedList, pageable, mergedEvents.size());
}

public ResponseEntity<?> storeManualEvent(ManualEventDto manualEventDto, Function<Event, Event> existingToNewEvent) {
Optional<Event> optionalEvent = eventRepository.
findFirstByInstanceFlowHeadersSourceApplicationIdAndInstanceFlowHeadersSourceApplicationInstanceIdAndInstanceFlowHeadersSourceApplicationIntegrationIdOrderByTimestampDesc(
manualEventDto.getSourceApplicationId(),
manualEventDto.getSourceApplicationInstanceId(),
manualEventDto.getSourceApplicationIntegrationId()
);

if (optionalEvent.isEmpty()) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Event not found.");
}

Event event = optionalEvent.get();

if (!event.getType().equals(EventType.ERROR)) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Event is not of type ERROR");
}

Event newEvent = existingToNewEvent.apply(event);

this.save(newEvent);

return ResponseEntity.ok(newEvent);
}

public Event createManualEvent(Event event, String name, String archiveId) {

InstanceFlowHeadersEmbeddable.InstanceFlowHeadersEmbeddableBuilder headersEmbeddableBuilder =
event.getInstanceFlowHeaders()
.toBuilder()
.correlationId(UUID.randomUUID());

if (archiveId != null && !archiveId.isEmpty()) {
headersEmbeddableBuilder.archiveInstanceId(archiveId);
}

InstanceFlowHeadersEmbeddable newInstanceFlowHeaders = headersEmbeddableBuilder.build();

return Event.builder()
.instanceFlowHeaders(newInstanceFlowHeaders)
.name(name)
.timestamp(OffsetDateTime.now())
.type(EventType.INFO)
.applicationId(event.getApplicationId())
.build();
}

public Page<EventDto> findAllByInstanceFlowHeadersSourceApplicationIdAndInstanceFlowHeadersSourceApplicationInstanceId(
Long sourceApplicationId,
String sourceApplicationInstanceId,
Pageable pageable
) {
return convertPageOfEventIntoPageOfEventDto(
eventRepository.findAllByInstanceFlowHeadersSourceApplicationIdAndInstanceFlowHeadersSourceApplicationInstanceId(
sourceApplicationId, sourceApplicationInstanceId, pageable
)
);
}

public Page<EventDto> findAllByInstanceFlowHeadersSourceApplicationIdIn(
List<Long> sourceApplicationIds,
Pageable pageable
) {
return convertPageOfEventIntoPageOfEventDto(
eventRepository.findAllByInstanceFlowHeadersSourceApplicationIdIn(
sourceApplicationIds,
pageable
)
);
}

private Page<EventDto> convertPageOfEventIntoPageOfEventDto(Page<Event> events) {
return events.map(this::EventToEventDto);
}

private EventDto EventToEventDto(Event event) {
return EventDto.builder()
.instanceFlowHeaders(event.getInstanceFlowHeaders())
.name(event.getName())
.timestamp(event.getTimestamp())
.type(event.getType())
.applicationId(event.getApplicationId())
.errors(event.getErrors())
.build();
}
}
86 changes: 19 additions & 67 deletions src/main/java/no/fintlabs/HistoryController.java
Original file line number Diff line number Diff line change
@@ -1,45 +1,43 @@
package no.fintlabs;

import no.fintlabs.model.*;
import no.fintlabs.repositories.EventRepository;
import no.fintlabs.resourceserver.security.user.UserAuthorizationUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.time.OffsetDateTime;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.function.Function;

import static no.fintlabs.resourceserver.UrlPaths.INTERNAL_API;

@RestController
@RequestMapping(INTERNAL_API + "/historikk")
public class HistoryController {

private final EventRepository eventRepository;
private final EventService eventService;
private final StatisticsService statisticsService;
@Value("${fint.flyt.resource-server.user-permissions-consumer.enabled:false}")
private boolean userPermissionsConsumerEnabled;

public HistoryController(EventRepository eventRepository, StatisticsService statisticsService) {
this.eventRepository = eventRepository;
public HistoryController(
EventService eventService,
StatisticsService statisticsService
) {
this.eventService = eventService;
this.statisticsService = statisticsService;
}

@GetMapping("hendelser")
public ResponseEntity<Page<Event>> getEvents(
public ResponseEntity<Page<EventDto>> getEvents(
@AuthenticationPrincipal Authentication authentication,
@RequestParam(name = "side") int page,
@RequestParam(name = "antall") int size,
Expand All @@ -54,7 +52,7 @@ public ResponseEntity<Page<Event>> getEvents(
return getResponseEntityEvents(authentication, pageRequest, onlyLatestPerInstance);
}

private ResponseEntity<Page<Event>> getResponseEntityEvents(
private ResponseEntity<Page<EventDto>> getResponseEntityEvents(
Authentication authentication,
Pageable pageable,
Optional<Boolean> onlyLatestPerInstance
Expand All @@ -65,22 +63,22 @@ private ResponseEntity<Page<Event>> getResponseEntityEvents(

return ResponseEntity.ok(
onlyLatestPerInstance.orElse(false)
? eventRepository
.findLatestEventPerSourceApplicationInstanceIdAndSourceApplicationIdIn(
? eventService
.getMergedLatestEventsWhereSourceApplicationIdIn(
sourceApplicationIds,
pageable
)
: eventRepository.findAllByInstanceFlowHeadersSourceApplicationIdIn(sourceApplicationIds, pageable));
: eventService.findAllByInstanceFlowHeadersSourceApplicationIdIn(sourceApplicationIds, pageable));
}
return ResponseEntity.ok(
onlyLatestPerInstance.orElse(false)
? eventRepository.findLatestEventPerSourceApplicationInstanceId(pageable)
: eventRepository.findAll(pageable)
? eventService.getMergedLatestEvents(pageable)
: eventService.findAll(pageable)
);
}

@GetMapping(path = "hendelser", params = {"kildeapplikasjonId", "kildeapplikasjonInstansId"})
public ResponseEntity<Page<Event>> getEventsWithInstanceId(
public ResponseEntity<Page<EventDto>> getEventsWithInstanceId(
@AuthenticationPrincipal Authentication authentication,
@RequestParam(name = "side") int page,
@RequestParam(name = "antall") int size,
Expand All @@ -97,7 +95,7 @@ public ResponseEntity<Page<Event>> getEventsWithInstanceId(
.withSort(sortDirection, sortProperty);

return ResponseEntity.ok(
eventRepository
eventService
.findAllByInstanceFlowHeadersSourceApplicationIdAndInstanceFlowHeadersSourceApplicationInstanceId(
sourceApplicationId,
sourceApplicationInstanceId,
Expand All @@ -114,9 +112,9 @@ public ResponseEntity<?> setManuallyProcessed(
if (userPermissionsConsumerEnabled) {
UserAuthorizationUtil.checkIfUserHasAccessToSourceApplication(authentication, manuallyProcessedEventDto.getSourceApplicationId());
}
return storeManualEvent(
return eventService.storeManualEvent(
manuallyProcessedEventDto,
existingEvent -> createManualEvent(
existingEvent -> eventService.createManualEvent(
existingEvent,
"instance-manually-processed",
manuallyProcessedEventDto.getArchiveInstanceId()
Expand All @@ -132,62 +130,16 @@ public ResponseEntity<?> setManuallyRejected(
if (userPermissionsConsumerEnabled) {
UserAuthorizationUtil.checkIfUserHasAccessToSourceApplication(authentication, manuallyRejectedEventDto.getSourceApplicationId());
}
return storeManualEvent(
return eventService.storeManualEvent(
manuallyRejectedEventDto,
existingEvent -> createManualEvent(
existingEvent -> eventService.createManualEvent(
existingEvent,
"instance-manually-rejected",
null
)
);
}

private ResponseEntity<?> storeManualEvent(ManualEventDto manualEventDto, Function<Event, Event> existingToNewEvent) {
Optional<Event> optionalEvent = eventRepository.
findFirstByInstanceFlowHeadersSourceApplicationIdAndInstanceFlowHeadersSourceApplicationInstanceIdAndInstanceFlowHeadersSourceApplicationIntegrationIdOrderByTimestampDesc(
manualEventDto.getSourceApplicationId(),
manualEventDto.getSourceApplicationInstanceId(),
manualEventDto.getSourceApplicationIntegrationId()
);

if (optionalEvent.isEmpty()) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Event not found.");
}

Event event = optionalEvent.get();

if (!event.getType().equals(EventType.ERROR)) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Event is not of type ERROR");
}

Event newEvent = existingToNewEvent.apply(event);

eventRepository.save(newEvent);

return ResponseEntity.ok(newEvent);
}

private Event createManualEvent(Event event, String name, String archiveId) {

InstanceFlowHeadersEmbeddable.InstanceFlowHeadersEmbeddableBuilder headersEmbeddableBuilder =
event.getInstanceFlowHeaders()
.toBuilder()
.correlationId(UUID.randomUUID());

if (archiveId != null && !archiveId.isEmpty()) {
headersEmbeddableBuilder.archiveInstanceId(archiveId);
}

InstanceFlowHeadersEmbeddable newInstanceFlowHeaders = headersEmbeddableBuilder.build();

return Event.builder()
.instanceFlowHeaders(newInstanceFlowHeaders)
.name(name)
.timestamp(OffsetDateTime.now())
.type(EventType.INFO)
.applicationId(event.getApplicationId())
.build();
}

@GetMapping("statistikk")
public ResponseEntity<Statistics> getStatistics(
Expand Down
23 changes: 23 additions & 0 deletions src/main/java/no/fintlabs/model/EventDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package no.fintlabs.model;

import lombok.*;

import java.time.OffsetDateTime;
import java.util.Collection;

@Getter
@Setter
@Builder(toBuilder = true)
@AllArgsConstructor
public class EventDto {
private InstanceFlowHeadersEmbeddable instanceFlowHeaders;
private String name;
private OffsetDateTime timestamp;
private EventType type;
private String applicationId;
private Collection<Error> errors;
private String status;

public EventDto() {
}
}
Loading

0 comments on commit 47009a1

Please sign in to comment.