Skip to content

Commit

Permalink
add implementation of custom spring events based on some internal logic
Browse files Browse the repository at this point in the history
  • Loading branch information
EMEA\VEA3SF committed Jan 21, 2024
1 parent ce9bf21 commit 2b66e05
Show file tree
Hide file tree
Showing 10 changed files with 436 additions and 224 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ Added integration with Docker.On every push event to main branch this action gen
- Spring Boot Actuator: https://www.baeldung.com/spring-boot-actuators
- Injecting Git Information Into Spring: https://www.baeldung.com/spring-git-information
- Quartz Job Scheduler with Cron Triggers and Expressions: https://www.quartz-scheduler.org/
- Spring Custom Events: https://www.baeldung.com/spring-events

# Branches:
- Branch with name: "java11Version" is set up for JDK11
Expand Down
20 changes: 20 additions & 0 deletions src/main/java/com/springpageable/event/ProcessDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.springpageable.event;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serial;
import java.io.Serializable;
import java.util.UUID;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class ProcessDto implements Serializable {

@Serial
private static final long serialVersionUID = 1L;

private UUID nextAutoPlanSubJobUuid;
}
19 changes: 19 additions & 0 deletions src/main/java/com/springpageable/event/ProcessEvent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.springpageable.event;

import com.springpageable.model.FutureDevice;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import org.springframework.context.ApplicationEvent;

@Getter
@EqualsAndHashCode(callSuper = true)
public class ProcessEvent extends ApplicationEvent {

private final ProcessDto processDto;

public ProcessEvent(FutureDevice futureDevice, ProcessDto processDto) {
super(futureDevice);
this.processDto = processDto;
}

}
17 changes: 17 additions & 0 deletions src/main/java/com/springpageable/event/ProcessEventListener.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.springpageable.event;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

@Component
public class ProcessEventListener implements ApplicationListener<ProcessEvent> {

private static final Logger LOGGER = LoggerFactory.getLogger(ProcessEventListener.class);

@Override
public void onApplicationEvent(ProcessEvent event) {
LOGGER.info("Received spring custom event - {}", event.getProcessDto().getNextAutoPlanSubJobUuid());
}
}
27 changes: 27 additions & 0 deletions src/main/java/com/springpageable/event/ProcessEventPublisher.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.springpageable.event;

import com.springpageable.repository.FutureDeviceRepository;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;

import java.util.UUID;

@Component
public class ProcessEventPublisher {

private final FutureDeviceRepository futureDeviceRepository;
private ApplicationEventPublisher applicationEventPublisher;

public ProcessEventPublisher(FutureDeviceRepository futureDeviceRepository,
ApplicationEventPublisher applicationEventPublisher) {
this.futureDeviceRepository = futureDeviceRepository;
this.applicationEventPublisher = applicationEventPublisher;
}

public void publishCustomEvent() {
ProcessDto processDto = new ProcessDto(UUID.randomUUID());
var futureDevice = futureDeviceRepository.findById(1L).get();
var event = new ProcessEvent(futureDevice, processDto);
applicationEventPublisher.publishEvent(event);
}
}
153 changes: 81 additions & 72 deletions src/main/java/com/springpageable/service/FutureDeviceService.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.springpageable.dto.FutureDeviceDTO;
import com.springpageable.dto.GetFutureDeviceResponseDTO;
import com.springpageable.event.ProcessEventPublisher;
import com.springpageable.exception.ConflictException;
import com.springpageable.exception.ResourceNotFoundException;
import com.springpageable.model.mapper.FutureDeviceMapper;
Expand All @@ -15,87 +16,95 @@
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import java.util.stream.Collectors;

@Service
@Slf4j
public class FutureDeviceService {

private final FutureDeviceRepository futureDeviceRepository;
private final UserRepository userRepository;
private final FutureDeviceRepository futureDeviceRepository;
private final UserRepository userRepository;

private final FutureDeviceMapper futureDeviceMapper;

private final FutureDeviceMapper futureDeviceMapper;
private final ProcessEventPublisher applicationEventPublisher;

@Autowired
public FutureDeviceService(
FutureDeviceRepository futureDeviceRepository, FutureDeviceMapper futureDeviceMapper,UserRepository userRepository) {
this.futureDeviceRepository = futureDeviceRepository;
this.futureDeviceMapper = futureDeviceMapper;
this.userRepository=userRepository;
}
@Autowired
public FutureDeviceService(
FutureDeviceRepository futureDeviceRepository, FutureDeviceMapper futureDeviceMapper,
UserRepository userRepository,
ProcessEventPublisher applicationEventPublisher) {
this.futureDeviceRepository = futureDeviceRepository;
this.futureDeviceMapper = futureDeviceMapper;
this.userRepository = userRepository;
this.applicationEventPublisher = applicationEventPublisher;
}

/**
* Find all future devices
*
* @param p - pagination object containing page size, page number and sort parameters
* @param searchParameter - term to search by serialNumber, productId or customerName
* @return Page of {@link GetFutureDeviceResponseDTO}
*/
public Page<GetFutureDeviceResponseDTO> retrieveFutureDevices(
Pageable p, String searchParameter) {
var futureDevices = futureDeviceRepository.findFutureDevices(p,searchParameter);
if (futureDevices.isEmpty()) {
return Page.empty();
/**
* Find all future devices
*
* @param p
* - pagination object containing page size, page number and sort parameters
* @param searchParameter
* - term to search by serialNumber, productId or customerName
* @return Page of {@link GetFutureDeviceResponseDTO}
*/
public Page<GetFutureDeviceResponseDTO> retrieveFutureDevices(
Pageable p, String searchParameter) {
var futureDevices = futureDeviceRepository.findFutureDevices(p, searchParameter);
if (futureDevices.isEmpty()) {
return Page.empty();
}
var devices =
futureDevices.stream()
.map(futureDeviceMapper::futureDeviceToFutureDeviceResponseDTO)
.toList();
// trigger custom spring event
applicationEventPublisher.publishCustomEvent();
return new PageImpl<>(devices, p, devices.size());
}
var devices =
futureDevices.stream()
.map(futureDeviceMapper::futureDeviceToFutureDeviceResponseDTO)
.collect(Collectors.toList());
return new PageImpl<>(devices, p, devices.size());
}

/**
* Creates new record in device future table, containing combination between
* serialNumber,productId and customerId
*
* @param futureDeviceDTO - {@link FutureDeviceDTO} object containing the new data
*/
public void createFutureDevice(FutureDeviceDTO futureDeviceDTO) {
userRepository.findById(futureDeviceDTO.getCustomerId()).orElseThrow(() -> {
String errMsg = String.format("There is no customer with id %s", futureDeviceDTO.getCustomerId());
log.error(errMsg);
throw new ResourceNotFoundException(errMsg);
});
var futureDevice = futureDeviceMapper.futureDeviceDTOToFutureDevice(futureDeviceDTO);
try {
futureDeviceRepository.save(futureDevice);
} catch (DataIntegrityViolationException e) {
String errMsg =
String.format(
"Combination with serial number %s,productId %s and customerId %d already exists",
futureDeviceDTO.getSerialNumber(),
futureDeviceDTO.getProductId(),
futureDeviceDTO.getCustomerId());
log.error(errMsg);
throw new ConflictException(errMsg);
/**
* Creates new record in device future table, containing combination between serialNumber,productId and customerId
*
* @param futureDeviceDTO
* - {@link FutureDeviceDTO} object containing the new data
*/
public void createFutureDevice(FutureDeviceDTO futureDeviceDTO) {
userRepository.findById(futureDeviceDTO.getCustomerId()).orElseThrow(() -> {
String errMsg = String.format("There is no customer with id %s", futureDeviceDTO.getCustomerId());
log.error(errMsg);
throw new ResourceNotFoundException(errMsg);
});
var futureDevice = futureDeviceMapper.futureDeviceDTOToFutureDevice(futureDeviceDTO);
try {
futureDeviceRepository.save(futureDevice);
} catch (DataIntegrityViolationException e) {
String errMsg =
String.format(
"Combination with serial number %s,productId %s and customerId %d already exists",
futureDeviceDTO.getSerialNumber(),
futureDeviceDTO.getProductId(),
futureDeviceDTO.getCustomerId());
log.error(errMsg);
throw new ConflictException(errMsg);
}
}
}

/**
* Deletes a future device
*
* @param id - id of the device to be deleted
*/
public void deleteFutureDevice(long id) {
var futureDevice =
futureDeviceRepository
.findById(id)
.orElseThrow(
() -> {
String errMsg = String.format("No future device found for id: %d", id);
log.error(errMsg);
throw new ResourceNotFoundException(errMsg);
});
futureDeviceRepository.deleteById(futureDevice.getId());
}
/**
* Deletes a future device
*
* @param id
* - id of the device to be deleted
*/
public void deleteFutureDevice(long id) {
var futureDevice =
futureDeviceRepository
.findById(id)
.orElseThrow(
() -> {
String errMsg = String.format("No future device found for id: %d", id);
log.error(errMsg);
throw new ResourceNotFoundException(errMsg);
});
futureDeviceRepository.deleteById(futureDevice.getId());
}
}
31 changes: 16 additions & 15 deletions src/test/java/com/device/CountryStorageTest.java
Original file line number Diff line number Diff line change
@@ -1,27 +1,26 @@
package com.device;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.springpageable.storage.CountryStorage;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;

import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.List;

import static com.device.mock.Constants.*;
import static com.springpageable.storage.CountryStorage.*;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
import static com.device.mock.Constants.ALL_COUNTRIES_SIZE;
import static com.device.mock.Constants.COUNTRY_BG_KEY;
import static com.device.mock.Constants.COUNTRY_BG_VALUE;
import static com.device.mock.Constants.COUNTRY_DE_KEY;
import static com.device.mock.Constants.COUNTRY_DE_VALUE;
import static com.device.mock.Constants.EMPTY_STRING;
import static com.device.mock.Constants.NON_EXISTING_COUNTRY_CODE;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

@ExtendWith(MockitoExtension.class)
class CountryStorageTest {
Expand All @@ -42,7 +41,8 @@ void testThat_getCountriesByCountryCodes_returnsTheExpectedCountries() {
assertFalse(result.isEmpty());
assertEquals(2, result.size());
assertEquals(2, result.stream()
.filter(country -> country.getName().equals(COUNTRY_BG_VALUE) || country.getName().equals(COUNTRY_DE_VALUE))
.filter(country -> country.getName().equals(COUNTRY_BG_VALUE) || country.getName()
.equals(COUNTRY_DE_VALUE))
.count());
}

Expand Down Expand Up @@ -107,7 +107,8 @@ void testThat_areAllCountryCodesSupported_validatesProperly() {
// Act & Assert
assertTrue(countryStorage.areAllCountryCodesSupported(List.of(COUNTRY_BG_KEY, COUNTRY_DE_KEY)));
assertFalse(
countryStorage.areAllCountryCodesSupported(List.of(COUNTRY_BG_KEY, NON_EXISTING_COUNTRY_CODE, COUNTRY_DE_KEY)));
countryStorage.areAllCountryCodesSupported(
List.of(COUNTRY_BG_KEY, NON_EXISTING_COUNTRY_CODE, COUNTRY_DE_KEY)));
}

@Test
Expand Down
39 changes: 39 additions & 0 deletions src/test/java/com/device/event/ProcessEventListenerTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.device.event;

import com.springpageable.event.ProcessDto;
import com.springpageable.event.ProcessEvent;
import com.springpageable.event.ProcessEventListener;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import java.util.UUID;

import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
class ProcessEventListenerTest {

@Mock
private ProcessEvent event;

@InjectMocks
private ProcessEventListener eventListener;

@Test
void onApplicationEventTest() {
// Arrange
ProcessDto processDto = new ProcessDto(UUID.randomUUID());
when(event.getProcessDto()).thenReturn(processDto);

// Act
eventListener.onApplicationEvent(event);

// Assert
verify(event, times(1)).getProcessDto();
}
}
Loading

0 comments on commit 2b66e05

Please sign in to comment.