Refactor of History module (#184)
Co-authored-by: widlam <mikolaj.widla@gmail.com> Co-authored-by: Adam Bem <adam.bem@zoho.eu> Reviewed-on: #184 Reviewed-by: Adam Bem <bema@noreply.example.com> Co-authored-by: Mikolaj Widla <widlam@noreply.example.com> Co-committed-by: Mikolaj Widla <widlam@noreply.example.com>
This commit is contained in:
@@ -7,7 +7,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-parent</artifactId>
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
<version>2.3.1.RELEASE</version>
|
<version>2.7.11</version>
|
||||||
<relativePath/> <!-- lookup parent from repository -->
|
<relativePath/> <!-- lookup parent from repository -->
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
@@ -18,9 +18,10 @@
|
|||||||
<jedis.version>3.3.0</jedis.version>
|
<jedis.version>3.3.0</jedis.version>
|
||||||
<logback-redis-appender.version>1.1.6</logback-redis-appender.version>
|
<logback-redis-appender.version>1.1.6</logback-redis-appender.version>
|
||||||
<assertj.version>3.16.1</assertj.version>
|
<assertj.version>3.16.1</assertj.version>
|
||||||
<mapstruct.version>1.3.1.Final</mapstruct.version>
|
<mapstruct.version>1.5.5.Final</mapstruct.version>
|
||||||
<docker.image.prefix>Release11</docker.image.prefix>
|
<docker.image.prefix>Release11</docker.image.prefix>
|
||||||
<docker.image.name>${project.artifactId}</docker.image.name>
|
<docker.image.name>${project.artifactId}</docker.image.name>
|
||||||
|
<lombok.version>1.18.26</lombok.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@@ -57,21 +58,6 @@
|
|||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>com.cwbase</groupId>
|
|
||||||
<artifactId>logback-redis-appender</artifactId>
|
|
||||||
<version>${logback-redis-appender.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>redis.clients</groupId>
|
|
||||||
<artifactId>jedis</artifactId>
|
|
||||||
<version>${jedis.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.codehaus.jettison</groupId>
|
|
||||||
<artifactId>jettison</artifactId>
|
|
||||||
<version>1.4.1</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
@@ -101,6 +87,11 @@
|
|||||||
<artifactId>lombok</artifactId>
|
<artifactId>lombok</artifactId>
|
||||||
<version>${lombok.version}</version>
|
<version>${lombok.version}</version>
|
||||||
</path>
|
</path>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok-mapstruct-binding</artifactId>
|
||||||
|
<version>0.2.0</version>
|
||||||
|
</dependency>
|
||||||
</annotationProcessorPaths>
|
</annotationProcessorPaths>
|
||||||
<compilerArgs>
|
<compilerArgs>
|
||||||
<compilerArg>-Amapstruct.defaultComponentModel=spring</compilerArg>
|
<compilerArg>-Amapstruct.defaultComponentModel=spring</compilerArg>
|
||||||
|
|||||||
@@ -1,68 +0,0 @@
|
|||||||
package com.r11.tools.config;
|
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.context.annotation.PropertySource;
|
|
||||||
import org.springframework.core.env.Environment;
|
|
||||||
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
|
|
||||||
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
|
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
|
||||||
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;
|
|
||||||
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
|
|
||||||
import redis.clients.jedis.JedisPool;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class containing configuration for Redis db client
|
|
||||||
* @author Rafał Żukowicz
|
|
||||||
*/
|
|
||||||
@Configuration
|
|
||||||
@EnableRedisRepositories
|
|
||||||
@PropertySource("classpath:data-access.properties")
|
|
||||||
public class RedisConfig {
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private Environment environment;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bean of JedisPool - the Redis client. It stores requests in "the pool" and then fires them at Redis.
|
|
||||||
* It's considered super lightweight and fast client variant
|
|
||||||
* @return lightweight client of the Redis - the JedisPool
|
|
||||||
*/
|
|
||||||
@Bean
|
|
||||||
JedisPool jedisPool(){
|
|
||||||
final JedisPool pool = new JedisPool(environment.getProperty("redis.host"),
|
|
||||||
Integer.parseInt(environment.getProperty("redis.port")));
|
|
||||||
return pool;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bean of a factory for connenction object.
|
|
||||||
* It's initialized with Redis db url property and is fed to other methods.
|
|
||||||
* @return the factory for RedisTemplates
|
|
||||||
*/
|
|
||||||
@Bean
|
|
||||||
JedisConnectionFactory jedisConnectionFactory() {
|
|
||||||
RedisStandaloneConfiguration redisStandaloneConfiguration =
|
|
||||||
new RedisStandaloneConfiguration(Objects.requireNonNull(environment.getProperty("redis.host")),
|
|
||||||
Integer.parseInt(Objects.requireNonNull(environment.getProperty("redis.port"))));
|
|
||||||
return new JedisConnectionFactory(redisStandaloneConfiguration);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* RedisTemplate is the tool to store and retrieve given type (object) of hash from the database.
|
|
||||||
* It's like you could store your Java object by just naming it inside database. You might thing about it
|
|
||||||
* as of DAO.
|
|
||||||
* @return RedisTemplate the redis dao.
|
|
||||||
*/
|
|
||||||
@Bean
|
|
||||||
public RedisTemplate<String, Object> redisTemplate() {
|
|
||||||
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
|
|
||||||
redisTemplate.setConnectionFactory(jedisConnectionFactory());
|
|
||||||
redisTemplate.setExposeConnection(true);
|
|
||||||
redisTemplate.setDefaultSerializer(new GenericJackson2JsonRedisSerializer());
|
|
||||||
return redisTemplate;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
package com.r11.tools.configuration;
|
||||||
|
|
||||||
|
import com.r11.tools.repository.MockedResponseRepository;
|
||||||
|
import com.r11.tools.repository.RequestHistoryRepository;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
|
import org.springframework.scheduling.annotation.EnableAsync;
|
||||||
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Based on configuration deletes all outdated messages and history records from database.
|
||||||
|
*
|
||||||
|
* @author Mikołaj Widła
|
||||||
|
*/
|
||||||
|
|
||||||
|
@EnableScheduling
|
||||||
|
@EnableAsync
|
||||||
|
@Configuration
|
||||||
|
public class RetentionConfiguration {
|
||||||
|
|
||||||
|
private final MockedResponseRepository responseRepository;
|
||||||
|
private final RequestHistoryRepository historyRepository;
|
||||||
|
private final RetentionConfigurationProperties retentionProperties;
|
||||||
|
private final Logger log = LogManager.getRootLogger();
|
||||||
|
|
||||||
|
|
||||||
|
public RetentionConfiguration(MockedResponseRepository responseRepository,
|
||||||
|
RequestHistoryRepository historyRepository,
|
||||||
|
RetentionConfigurationProperties retentionProperties){
|
||||||
|
this.historyRepository = historyRepository;
|
||||||
|
this.responseRepository = responseRepository;
|
||||||
|
this.retentionProperties = retentionProperties;
|
||||||
|
}
|
||||||
|
@Scheduled(fixedDelayString = "#{${retention.retention-cooldown} * 60000 }")
|
||||||
|
@Async
|
||||||
|
public void deleteMessagesAndHistoryRecords(){
|
||||||
|
log.info("OUTDATED MESSAGES AND HISTORY RECORDS DELETED!");
|
||||||
|
responseRepository
|
||||||
|
.findAll()
|
||||||
|
.iterator()
|
||||||
|
.forEachRemaining( mockedMessage -> {
|
||||||
|
if (mockedMessage.getCreatedAt().plusMinutes(retentionProperties.getMinutesToDeleteMessage()).isBefore(LocalDateTime.now())){
|
||||||
|
responseRepository.delete(mockedMessage);
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
historyRepository
|
||||||
|
.findAll()
|
||||||
|
.iterator()
|
||||||
|
.forEachRemaining(
|
||||||
|
historyRecord -> {
|
||||||
|
if (historyRecord.getDateTimeStamp().plusMinutes(retentionProperties.getMinutesToDeleteHistoryRecord()).isBefore(LocalDateTime.now())){
|
||||||
|
historyRepository.delete(historyRecord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package com.r11.tools.configuration;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import javax.validation.constraints.Positive;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store all properties needed to change a retention in {@link RetentionConfiguration}
|
||||||
|
*
|
||||||
|
* @author Mikołaj Widła
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ConfigurationProperties(prefix = "retention")
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class RetentionConfigurationProperties {
|
||||||
|
@Positive
|
||||||
|
private Integer minutesToDeleteMessage;
|
||||||
|
@Positive
|
||||||
|
private Integer minutesToDeleteHistoryRecord;
|
||||||
|
@Positive
|
||||||
|
private Integer retentionCooldown;
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package com.r11.tools.configuration;
|
||||||
|
|
||||||
|
import com.r11.tools.interceptor.IncomingMockRequestInterceptor;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||||
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration for {@link IncomingMockRequestInterceptor}
|
||||||
|
*
|
||||||
|
* @author Mikołaj Widła
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class WebConfig implements WebMvcConfigurer{
|
||||||
|
|
||||||
|
private final IncomingMockRequestInterceptor requestInterceptor;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addInterceptors(InterceptorRegistry registry) {
|
||||||
|
registry.addInterceptor( requestInterceptor )
|
||||||
|
.addPathPatterns("/api/mock/r/**");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
package com.r11.tools.controller;
|
|
||||||
|
|
||||||
import com.r11.tools.model.EventRequestDto;
|
|
||||||
import com.r11.tools.service.EtrackService;
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* It's the REST api for {@link com.r11.tools.model.Event}
|
|
||||||
* @author Gabriel Modzelewski
|
|
||||||
*/
|
|
||||||
@RestController
|
|
||||||
@RequestMapping(path = "/api/event")
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class EventController {
|
|
||||||
private final EtrackService service;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the list of Events in given time bracket.
|
|
||||||
* The list of objects is received via {@link EventRequestDto}, which contains time brackets,
|
|
||||||
* as well as the key - uuid.
|
|
||||||
* @param event EventRequestDto object that contains data needed to query the database
|
|
||||||
* @return list of {@link com.r11.tools.model.Event}
|
|
||||||
*/
|
|
||||||
@PostMapping
|
|
||||||
public ResponseEntity filterHistory(@RequestBody EventRequestDto event){
|
|
||||||
return new ResponseEntity(service.getEventsByDateTimeAndBusinessKeys(event), HttpStatus.OK);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the list of Events of last 24h from given date.
|
|
||||||
* @param uuid unique id of message list
|
|
||||||
* @param messageId unique id of message in message list
|
|
||||||
* @return list of {@link com.r11.tools.model.Event}
|
|
||||||
*/
|
|
||||||
@GetMapping(path = "/{uuid}/{messageId}")
|
|
||||||
public ResponseEntity getLastDay(@PathVariable UUID uuid,
|
|
||||||
@PathVariable Integer messageId){
|
|
||||||
LocalDateTime requestTime = LocalDateTime.now();
|
|
||||||
LocalDateTime dayBeforeRequest = requestTime.minusDays(1L);
|
|
||||||
EventRequestDto eventRequestDto = EventRequestDto.builder()
|
|
||||||
.clientUUID(uuid)
|
|
||||||
.mockedResponseId(messageId)
|
|
||||||
.localDateTimeFrom(dayBeforeRequest)
|
|
||||||
.localDateTimeTo(requestTime)
|
|
||||||
.build();
|
|
||||||
return new ResponseEntity(service.getEventsByDateTimeAndBusinessKeys(eventRequestDto), HttpStatus.OK);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -3,13 +3,14 @@ package com.r11.tools.controller;
|
|||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.r11.tools.model.MockedMessageDto;
|
import com.r11.tools.model.MockedMessageDto;
|
||||||
import com.r11.tools.service.KlausService;
|
import com.r11.tools.service.KlausService;
|
||||||
import com.r11.tools.utilis.BusinessKey;
|
|
||||||
import com.r11.tools.utilis.TrackingClient;
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.springframework.http.*;
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
@@ -18,17 +19,19 @@ import java.util.*;
|
|||||||
/**
|
/**
|
||||||
* Returns the homepage and provides the api for javascript async requests.
|
* Returns the homepage and provides the api for javascript async requests.
|
||||||
* @author Gabriel Modzelewski
|
* @author Gabriel Modzelewski
|
||||||
|
* @author Mikołaj Widła
|
||||||
*/
|
*/
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping(path = "/api/mock")
|
@RequestMapping(path = "/api/mock")
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
|
@CrossOrigin(origins = "*")
|
||||||
public class MockController {
|
public class MockController {
|
||||||
private final KlausService klausService;
|
private final KlausService klausService;
|
||||||
private final Logger log = LogManager.getRootLogger();
|
private final Logger log = LogManager.getRootLogger();
|
||||||
|
|
||||||
@ExceptionHandler(Exception.class)
|
@ExceptionHandler(Exception.class)
|
||||||
public void errorHandler(Exception ex){
|
public void errorHandler(Exception ex){
|
||||||
log.error(ex.getStackTrace());
|
log.error(Arrays.toString(ex.getStackTrace()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -175,22 +178,14 @@ public class MockController {
|
|||||||
/**
|
/**
|
||||||
* It's one of the most important features - the bread and butter of the Mocked Service. It's link that allows
|
* It's one of the most important features - the bread and butter of the Mocked Service. It's link that allows
|
||||||
* to receive mocked response from the server and use it to mock!
|
* to receive mocked response from the server and use it to mock!
|
||||||
* @param requestEntity Logs the data of request
|
|
||||||
* @param clientUUID the key-uuid of given set of messages
|
* @param clientUUID the key-uuid of given set of messages
|
||||||
* @param mockedResponseId unique id of given message
|
* @param mockedResponseId unique id of given message
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@GetMapping(value = "/r/{clientUUID}/{mockedResponseId}")
|
@RequestMapping(value = "/r/{clientUUID}/{mockedResponseId}")
|
||||||
public ResponseEntity getMockedResponse(RequestEntity<String> requestEntity,
|
public ResponseEntity getMockedResponse(
|
||||||
@PathVariable UUID clientUUID,
|
@PathVariable UUID clientUUID,
|
||||||
@PathVariable int mockedResponseId) {
|
@PathVariable int mockedResponseId) {
|
||||||
TrackingClient.setBusinessKeys(Map.of(BusinessKey.INTERFACE_NAME, "getMockedResponse - request",
|
|
||||||
BusinessKey.CLIENT_UUID, String.valueOf(clientUUID),
|
|
||||||
BusinessKey.MESSAGE_ID, String.valueOf(mockedResponseId)));
|
|
||||||
// log.info(requestEntity.toString().replaceAll("\"", "\\\\\"").substring(1).replaceAll("\n",""));
|
|
||||||
TrackingClient.setBusinessKeys(Map.of(BusinessKey.INTERFACE_NAME, "getMockedResponse - response",
|
|
||||||
BusinessKey.CLIENT_UUID, String.valueOf(clientUUID),
|
|
||||||
BusinessKey.MESSAGE_ID, String.valueOf(mockedResponseId)));
|
|
||||||
MockedMessageDto mockedMessageDto = klausService.getMockedResponse(clientUUID, mockedResponseId);
|
MockedMessageDto mockedMessageDto = klausService.getMockedResponse(clientUUID, mockedResponseId);
|
||||||
HttpHeaders httpHeaders = new HttpHeaders();
|
HttpHeaders httpHeaders = new HttpHeaders();
|
||||||
if (mockedMessageDto.getHttpHeaders() != null) mockedMessageDto.getHttpHeaders().forEach(httpHeaders::set);
|
if (mockedMessageDto.getHttpHeaders() != null) mockedMessageDto.getHttpHeaders().forEach(httpHeaders::set);
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import org.springframework.http.HttpStatus;
|
|||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.validation.BindException;
|
import org.springframework.validation.BindException;
|
||||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||||
|
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
|
|
||||||
|
|
||||||
@@ -15,6 +16,7 @@ import org.springframework.web.bind.annotation.ExceptionHandler;
|
|||||||
* @author Rafał Żukowicz
|
* @author Rafał Żukowicz
|
||||||
*/
|
*/
|
||||||
@ControllerAdvice
|
@ControllerAdvice
|
||||||
|
@CrossOrigin(origins = "*")
|
||||||
public class MvcExceptionHandler {
|
public class MvcExceptionHandler {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
package com.r11.tools.controller;
|
||||||
|
|
||||||
|
import com.r11.tools.mappers.RequestHistoryMapper;
|
||||||
|
import com.r11.tools.model.HistoryRequestModel;
|
||||||
|
import com.r11.tools.model.RequestHistory;
|
||||||
|
import com.r11.tools.model.RequestHistoryDTO;
|
||||||
|
import com.r11.tools.service.RequestHistoryService;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* It's the REST api for {@link RequestHistory}
|
||||||
|
* @author Gabriel Modzelewski
|
||||||
|
* @author Mikołaj Widła
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(path = "/api/event")
|
||||||
|
@AllArgsConstructor
|
||||||
|
@CrossOrigin(origins = "*")
|
||||||
|
public class RequestHistoryController {
|
||||||
|
private final RequestHistoryService service;
|
||||||
|
private final RequestHistoryMapper mapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of Events in given time bracket.
|
||||||
|
* The list of objects is received via {@link RequestHistoryDTO}, which contains time brackets,
|
||||||
|
* as well as the key - uuid.
|
||||||
|
* @param historyRequestModel EventRequestDto object that contains data needed to query the database
|
||||||
|
* @return list of {@link RequestHistory}
|
||||||
|
*/
|
||||||
|
@PostMapping
|
||||||
|
public ResponseEntity<List<RequestHistoryDTO>> filterHistory(@RequestBody HistoryRequestModel historyRequestModel){
|
||||||
|
return ResponseEntity.ok(
|
||||||
|
service.getHistoryRecordsBetweenDatesAndByUUIDAndMessageId(historyRequestModel)
|
||||||
|
.stream()
|
||||||
|
.map(mapper::requestHistoryToRequestHistoryDTO)
|
||||||
|
.collect(Collectors.toList())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of Events of last 24h from given date.
|
||||||
|
* @param uuid unique id of message list
|
||||||
|
* @param messageId unique id of message in message list
|
||||||
|
* @return list of {@link RequestHistory}
|
||||||
|
*/
|
||||||
|
@GetMapping(path = "/{uuid}/{messageId}")
|
||||||
|
public ResponseEntity<List<RequestHistoryDTO>> getLastDay(@PathVariable UUID uuid,
|
||||||
|
@PathVariable Integer messageId){
|
||||||
|
LocalDateTime requestTime = LocalDateTime.now();
|
||||||
|
LocalDateTime dayBeforeRequest = requestTime.minusDays(1L);
|
||||||
|
List<RequestHistoryDTO> requestHistory = service.getHistoryRecordsBetweenDatesAndByUUIDAndMessageId(
|
||||||
|
HistoryRequestModel.builder()
|
||||||
|
.localDateTimeFrom(dayBeforeRequest)
|
||||||
|
.localDateTimeTo(requestTime)
|
||||||
|
.clientUUID(uuid)
|
||||||
|
.mockedResponseId(messageId)
|
||||||
|
.build()
|
||||||
|
).stream()
|
||||||
|
.map(mapper::requestHistoryToRequestHistoryDTO)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
return ResponseEntity.ok(requestHistory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
package com.r11.tools.interceptor;
|
||||||
|
|
||||||
|
import com.r11.tools.model.RequestHistoryDTO;
|
||||||
|
import com.r11.tools.service.RequestHistoryService;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.StreamUtils;
|
||||||
|
import org.springframework.web.servlet.HandlerInterceptor;
|
||||||
|
import org.springframework.web.servlet.HandlerMapping;
|
||||||
|
import org.springframework.web.util.ContentCachingRequestWrapper;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.StreamSupport;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interceptor that gets needed data from HttpRequest, and saves it to history
|
||||||
|
* @author Mikołaj Widła
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class IncomingMockRequestInterceptor implements HandlerInterceptor {
|
||||||
|
|
||||||
|
private final RequestHistoryService historyService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean preHandle(HttpServletRequest httpRequest, HttpServletResponse response, Object handler){
|
||||||
|
Map<String,String> headers = getHeadersFromHttpRequest(httpRequest);
|
||||||
|
Map<String,String> pathVariable = getPathVariablesFromHttpRequest(httpRequest);
|
||||||
|
String requestBody = getRequestBodyFromHttpRequest(httpRequest);
|
||||||
|
|
||||||
|
RequestHistoryDTO historyDTO = RequestHistoryDTO.builder()
|
||||||
|
.httpMethod(HttpMethod.valueOf(httpRequest.getMethod()))
|
||||||
|
.headers( headers )
|
||||||
|
.messageID(Integer.valueOf(pathVariable.get("mockedResponseId")))
|
||||||
|
.clientUUID(UUID.fromString(pathVariable.get("clientUUID")))
|
||||||
|
.dateTimeStamp(LocalDateTime.now())
|
||||||
|
.requestBody(requestBody)
|
||||||
|
.build();
|
||||||
|
historyService.saveRequest(historyDTO);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String,String> getHeadersFromHttpRequest( HttpServletRequest httpRequest ){
|
||||||
|
Set<String> headersName = StreamSupport.stream(
|
||||||
|
Spliterators.spliteratorUnknownSize(
|
||||||
|
httpRequest.getHeaderNames().asIterator(),
|
||||||
|
Spliterator.ORDERED
|
||||||
|
), false
|
||||||
|
).collect(Collectors.toSet());
|
||||||
|
|
||||||
|
return headersName.stream()
|
||||||
|
.collect(Collectors.toMap(
|
||||||
|
value -> value,
|
||||||
|
httpRequest::getHeader
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String,String> getPathVariablesFromHttpRequest( HttpServletRequest httpRequest ){
|
||||||
|
return (Map<String, String>) httpRequest.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getRequestBodyFromHttpRequest( HttpServletRequest httpRequest ){
|
||||||
|
HttpServletRequest wrappedRequest = new ContentCachingRequestWrapper(httpRequest);
|
||||||
|
try {
|
||||||
|
return StreamUtils.copyToString(wrappedRequest.getInputStream(), Charset.defaultCharset());
|
||||||
|
} catch (IOException e) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -12,6 +12,7 @@ import org.mapstruct.*;
|
|||||||
public interface MockedMessageMapper {
|
public interface MockedMessageMapper {
|
||||||
@Mapping( target = "compositePrimaryKey", expression = "java(mockedMessageDto.getClientUUID() + \"_\"" +
|
@Mapping( target = "compositePrimaryKey", expression = "java(mockedMessageDto.getClientUUID() + \"_\"" +
|
||||||
" + mockedMessageDto.getMockedResponseId())")
|
" + mockedMessageDto.getMockedResponseId())")
|
||||||
|
@Mapping( target = "createdAt" , expression = "java(java.time.LocalDateTime.now())")
|
||||||
MockedMessage mockedMessageDtoToMockedMessage(MockedMessageDto mockedMessageDto);
|
MockedMessage mockedMessageDtoToMockedMessage(MockedMessageDto mockedMessageDto);
|
||||||
MockedMessageDto mockedMessageToMockedMessageDto(MockedMessage mockedMessage);
|
MockedMessageDto mockedMessageToMockedMessageDto(MockedMessage mockedMessage);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package com.r11.tools.mappers;
|
||||||
|
|
||||||
|
import com.r11.tools.model.RequestHistory;
|
||||||
|
import com.r11.tools.model.RequestHistoryDTO;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.Mapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map between DTO and Entity
|
||||||
|
*
|
||||||
|
* @author Mikołaj Widła
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface RequestHistoryMapper {
|
||||||
|
|
||||||
|
@Mapping(target = "id", expression = "java(null)")
|
||||||
|
@Mapping(target = "clientUUID", expression = "java(requestHistoryDTO.getClientUUID().toString())")
|
||||||
|
RequestHistory requestHistoryDTOToRequestHistory(RequestHistoryDTO requestHistoryDTO);
|
||||||
|
@Mapping(target = "clientUUID", expression = "java(java.util.UUID.fromString(requestHistory.getClientUUID()))")
|
||||||
|
RequestHistoryDTO requestHistoryToRequestHistoryDTO(RequestHistory requestHistory);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
package com.r11.tools.model;
|
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import lombok.*;
|
|
||||||
import org.springframework.format.annotation.DateTimeFormat;
|
|
||||||
import org.springframework.lang.Nullable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pojo class for Event entity
|
|
||||||
* @author Rafał Żukowicz
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Builder
|
|
||||||
@ToString
|
|
||||||
@NoArgsConstructor
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class Event implements Comparable<Event>{
|
|
||||||
|
|
||||||
@DateTimeFormat(pattern = "yyyy-MM-ddTHH:mm:ss")
|
|
||||||
private LocalDateTime dateTimeStamp;
|
|
||||||
@Nullable
|
|
||||||
private String interfaceName;
|
|
||||||
@Nullable
|
|
||||||
private String clientUUID;
|
|
||||||
@Nullable
|
|
||||||
private Integer messageId;
|
|
||||||
private String thread;
|
|
||||||
private String level;
|
|
||||||
@Nullable
|
|
||||||
private String message;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compareTo(Event o) {
|
|
||||||
return this.getDateTimeStamp().compareTo(o.getDateTimeStamp()) * -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +1,24 @@
|
|||||||
package com.r11.tools.model;
|
package com.r11.tools.model;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.util.UUID;
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import org.springframework.format.annotation.DateTimeFormat;
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pojo for history query request. Contains information necessary to obtain {@link Event} list
|
* Represents all data needed to get HistoryRecord from database
|
||||||
* @author Rafał Żukowicz
|
* @author Mikołaj Widła
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@Builder
|
@Builder
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class EventRequestDto {
|
public class HistoryRequestModel {
|
||||||
|
|
||||||
private UUID clientUUID;
|
private UUID clientUUID;
|
||||||
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
|
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
|
||||||
@@ -2,6 +2,7 @@ package com.r11.tools.model;
|
|||||||
|
|
||||||
import com.r11.tools.model.constraints.HttpCode;
|
import com.r11.tools.model.constraints.HttpCode;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import javax.validation.constraints.Positive;
|
import javax.validation.constraints.Positive;
|
||||||
@@ -34,6 +35,7 @@ public class MockedMessage implements Serializable {
|
|||||||
private Map<String, String> httpHeaders;
|
private Map<String, String> httpHeaders;
|
||||||
@HttpCode
|
@HttpCode
|
||||||
private Integer httpStatus;
|
private Integer httpStatus;
|
||||||
|
private LocalDateTime createdAt;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package com.r11.tools.model;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import org.springframework.data.annotation.Id;
|
||||||
|
import org.springframework.data.redis.core.RedisHash;
|
||||||
|
import org.springframework.data.redis.core.index.Indexed;
|
||||||
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pojo class for Event entity
|
||||||
|
* @author Rafał Żukowicz
|
||||||
|
* @author Mikołaj Widła
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@RedisHash("mockHistory")
|
||||||
|
public class RequestHistory implements Comparable<RequestHistory>, Serializable {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private String id;
|
||||||
|
@DateTimeFormat(pattern = "yyyy-MM-ddTHH:mm:ss")
|
||||||
|
private LocalDateTime dateTimeStamp;
|
||||||
|
@Indexed
|
||||||
|
private String clientUUID;
|
||||||
|
@Indexed
|
||||||
|
private Integer messageID;
|
||||||
|
private Map<String,String> headers;
|
||||||
|
private HttpMethod httpMethod;
|
||||||
|
private String requestBody;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(RequestHistory o) {
|
||||||
|
return this.getDateTimeStamp().compareTo(o.getDateTimeStamp()) * -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.r11.tools.model;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pojo for history query request. Contains information necessary to obtain {@link RequestHistory} list
|
||||||
|
* @author Rafał Żukowicz
|
||||||
|
* @author Mikołaj Widła
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class RequestHistoryDTO {
|
||||||
|
|
||||||
|
private UUID clientUUID;
|
||||||
|
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
|
||||||
|
private LocalDateTime dateTimeStamp;
|
||||||
|
private Integer messageID;
|
||||||
|
private Map<String,String> headers;
|
||||||
|
private HttpMethod httpMethod;
|
||||||
|
private String requestBody;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
package com.r11.tools.repository;
|
|
||||||
|
|
||||||
import com.r11.tools.model.Event;
|
|
||||||
import com.r11.tools.utilis.BusinessKey;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import org.springframework.stereotype.Repository;
|
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Event entity dao interface
|
|
||||||
* @author Rafał Żukowicz
|
|
||||||
*/
|
|
||||||
@Repository
|
|
||||||
@Transactional
|
|
||||||
public interface EventRepository {
|
|
||||||
List<Event> findEvents(LocalDateTime localDateTimeFrom, LocalDateTime localDateTimeTo,
|
|
||||||
Map<BusinessKey, String> businessKeys);
|
|
||||||
}
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
package com.r11.tools.repository;
|
|
||||||
|
|
||||||
import static com.r11.tools.utilis.RedisAppender.LOG_PREFIX;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import com.r11.tools.model.Event;
|
|
||||||
import com.r11.tools.utilis.BusinessKey;
|
|
||||||
import java.time.LocalDate;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.time.LocalTime;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import org.springframework.stereotype.Repository;
|
|
||||||
import redis.clients.jedis.Jedis;
|
|
||||||
import redis.clients.jedis.JedisPool;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds Event list based on logs created via {@link com.r11.tools.utilis.TrackingClient} and {@link com.r11.tools.utilis.RedisAppender}
|
|
||||||
* @author Rafał Żukowicz
|
|
||||||
*/
|
|
||||||
@Repository
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class EventRepositoryImpl implements EventRepository {
|
|
||||||
private final JedisPool jedisPool;
|
|
||||||
private final ObjectMapper objectMapper;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates list of {@link Event} based on {@link com.r11.tools.model.EventRequestDto} data via searching logs
|
|
||||||
* @param localDateTimeFrom date from which logs are retrieved
|
|
||||||
* @param localDateTimeTo date to which logs are retrieved
|
|
||||||
* @param businessKeys set keys for redis values
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public List<Event> findEvents(LocalDateTime localDateTimeFrom, LocalDateTime localDateTimeTo,
|
|
||||||
Map<BusinessKey, String> businessKeys) {
|
|
||||||
List<String> eventStrings = findEventsBetweenDates(localDateTimeFrom.toLocalDate(), localDateTimeTo.toLocalDate());
|
|
||||||
if (businessKeys.size() > 0) {
|
|
||||||
eventStrings = businessKeysFilter(eventStrings, businessKeys);
|
|
||||||
}
|
|
||||||
List<Event> events = parseEvents(eventStrings);
|
|
||||||
if (localDateTimeFrom.toLocalTime() != LocalTime.MIN) {
|
|
||||||
events = events.stream().filter(event -> event.getDateTimeStamp().compareTo(localDateTimeFrom) >= 0)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
return events.stream().filter(event -> event.getDateTimeStamp().compareTo(localDateTimeTo) <= 0)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns logs between given dates
|
|
||||||
* @param localDateFrom date from which logs are retrieved
|
|
||||||
* @param localDateTo date to which logs are retrieved
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private List<String> findEventsBetweenDates(LocalDate localDateFrom, LocalDate localDateTo) {
|
|
||||||
try (Jedis jedis = jedisPool.getResource()) {
|
|
||||||
return localDateFrom.datesUntil(localDateTo.plusDays(1)).map(day -> LOG_PREFIX + day.toString())
|
|
||||||
.map(key -> jedis.lrange(key, 0, -1)).flatMap(Collection::stream).collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Filters keys so only the ones queried are retirned
|
|
||||||
* @param events list of logs
|
|
||||||
* @param businessKeys set keys for redis values
|
|
||||||
* @return filtered list of logs
|
|
||||||
*/
|
|
||||||
private List<String> businessKeysFilter(List<String> events, Map<BusinessKey, String> businessKeys) {
|
|
||||||
for (Map.Entry<BusinessKey, String> entry : businessKeys.entrySet()) {
|
|
||||||
String stringPattern = entry.getKey().getReasonPhrase()+ "\"" + ":" + "\"" + entry.getValue() + "\"";
|
|
||||||
events = events.stream().filter(s -> s.contains(stringPattern)).collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
return events;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses list of logs into list of {@link Event}
|
|
||||||
* @param eventStrings list of logs
|
|
||||||
* @return list of {@link Event}
|
|
||||||
*/
|
|
||||||
private List<Event> parseEvents(List<String> eventStrings) {
|
|
||||||
List<Event> events = new ArrayList<>();
|
|
||||||
for (String eventString : eventStrings) {
|
|
||||||
eventString = eventString.replaceAll("\\R", "");
|
|
||||||
try {
|
|
||||||
events.add(objectMapper.readValue(eventString, Event.class));
|
|
||||||
} catch (JsonProcessingException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return events;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package com.r11.tools.repository;
|
||||||
|
|
||||||
|
import com.r11.tools.model.RequestHistory;
|
||||||
|
import org.springframework.data.repository.CrudRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* History Record entity dao interface
|
||||||
|
* @author Rafał Żukowicz
|
||||||
|
*/
|
||||||
|
@Repository
|
||||||
|
@Transactional
|
||||||
|
public interface RequestHistoryRepository extends CrudRepository<RequestHistory,String> {
|
||||||
|
List<RequestHistory> findAllByClientUUIDAndMessageID(
|
||||||
|
String clientUUID,
|
||||||
|
Integer messageID);
|
||||||
|
}
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
package com.r11.tools.service;
|
|
||||||
|
|
||||||
import com.r11.tools.model.Event;
|
|
||||||
import com.r11.tools.model.EventRequestDto;
|
|
||||||
import java.util.List;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Spring service interface for {@link com.r11.tools.controller.EventController}
|
|
||||||
* @author Rafał Żukowicz
|
|
||||||
*/
|
|
||||||
@Service
|
|
||||||
public interface EtrackService {
|
|
||||||
/**
|
|
||||||
* Searches for {@link Event} objects between date brackets
|
|
||||||
* @param eventsDto object containing required data for request
|
|
||||||
* @return list of {@link Event}
|
|
||||||
*/
|
|
||||||
List<Event> getEventsByDateTimeAndBusinessKeys(EventRequestDto eventsDto);
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
package com.r11.tools.service;
|
|
||||||
|
|
||||||
import com.r11.tools.model.Event;
|
|
||||||
import com.r11.tools.model.EventRequestDto;
|
|
||||||
import com.r11.tools.repository.EventRepository;
|
|
||||||
import com.r11.tools.utilis.BusinessKey;
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Spring Service for {@link com.r11.tools.controller.EventController}. Contains logic required for quering
|
|
||||||
* the database for {@link Event} objects
|
|
||||||
* @author Rafał Żukowicz
|
|
||||||
*/
|
|
||||||
@Service
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class EtrackServiceImpl implements EtrackService {
|
|
||||||
|
|
||||||
private final EventRepository eventRepository;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds {@link BusinessKey} to {@link EventRequestDto}
|
|
||||||
* in order to create query via{@link com.r11.tools.repository.EventRepositoryImpl}
|
|
||||||
* @param eventsDto object containing required data for request
|
|
||||||
* @return list of {@link Event}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public List<Event> getEventsByDateTimeAndBusinessKeys(EventRequestDto eventsDto) {
|
|
||||||
Map<BusinessKey, String> businessKeys = new HashMap<>();
|
|
||||||
businessKeys.put(BusinessKey.CLIENT_UUID, eventsDto.getClientUUID().toString());
|
|
||||||
if (eventsDto.getMockedResponseId() != null){
|
|
||||||
businessKeys.put(BusinessKey.MESSAGE_ID, String.valueOf(eventsDto.getMockedResponseId()));
|
|
||||||
}
|
|
||||||
List<Event> events = eventRepository.findEvents(eventsDto.getLocalDateTimeFrom(), eventsDto.getLocalDateTimeTo(),
|
|
||||||
businessKeys);
|
|
||||||
Collections.sort(events);
|
|
||||||
return events;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
package com.r11.tools.service;
|
package com.r11.tools.service;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import com.r11.tools.mappers.MockedMessageMapper;
|
import com.r11.tools.mappers.MockedMessageMapper;
|
||||||
import com.r11.tools.model.MockedMessage;
|
import com.r11.tools.model.MockedMessage;
|
||||||
import com.r11.tools.model.MockedMessageDto;
|
import com.r11.tools.model.MockedMessageDto;
|
||||||
@@ -13,6 +12,7 @@ import org.springframework.http.HttpHeaders;
|
|||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@@ -30,7 +30,6 @@ public class KlausServiceImpl implements KlausService {
|
|||||||
private final MockedMessageMapper mockedMessageMapper;
|
private final MockedMessageMapper mockedMessageMapper;
|
||||||
private final Logger log = LogManager.getRootLogger();
|
private final Logger log = LogManager.getRootLogger();
|
||||||
private final MockedResponseRepository mockedResponseRepository;
|
private final MockedResponseRepository mockedResponseRepository;
|
||||||
private final ObjectMapper objectMapper;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes message of given id in given key-uuid set
|
* Removes message of given id in given key-uuid set
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.r11.tools.service;
|
||||||
|
|
||||||
|
import com.r11.tools.controller.RequestHistoryController;
|
||||||
|
import com.r11.tools.model.HistoryRequestModel;
|
||||||
|
import com.r11.tools.model.RequestHistory;
|
||||||
|
import com.r11.tools.model.RequestHistoryDTO;
|
||||||
|
import java.util.List;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spring service interface for {@link RequestHistoryController}
|
||||||
|
* @author Rafał Żukowicz
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public interface RequestHistoryService {
|
||||||
|
/**
|
||||||
|
* Searches for {@link RequestHistory} objects between date brackets
|
||||||
|
* @param historyRequestModel object containing required data for request
|
||||||
|
* @return list of {@link RequestHistory}
|
||||||
|
*/
|
||||||
|
List<RequestHistory> getHistoryRecordsBetweenDatesAndByUUIDAndMessageId(HistoryRequestModel historyRequestModel);
|
||||||
|
void saveRequest(RequestHistoryDTO requestDTO);
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package com.r11.tools.service;
|
||||||
|
|
||||||
|
import com.r11.tools.controller.RequestHistoryController;
|
||||||
|
import com.r11.tools.mappers.RequestHistoryMapper;
|
||||||
|
import com.r11.tools.model.HistoryRequestModel;
|
||||||
|
import com.r11.tools.model.RequestHistory;
|
||||||
|
import com.r11.tools.model.RequestHistoryDTO;
|
||||||
|
import com.r11.tools.repository.RequestHistoryRepository;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spring Service for {@link RequestHistoryController}. Contains logic required for quering
|
||||||
|
* the database for {@link RequestHistory} objects
|
||||||
|
* @author Rafał Żukowicz
|
||||||
|
* @author Mikołaj Widła
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class RequestHistoryServiceImpl implements RequestHistoryService {
|
||||||
|
|
||||||
|
private final RequestHistoryRepository repository;
|
||||||
|
private final RequestHistoryMapper requestMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* in order to create query via{@link com.r11.tools.repository.RequestHistoryRepository}
|
||||||
|
* @param historyRequestModel object containing required data for request
|
||||||
|
* @return list of {@link RequestHistory}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<RequestHistory> getHistoryRecordsBetweenDatesAndByUUIDAndMessageId(HistoryRequestModel historyRequestModel) {
|
||||||
|
List<RequestHistory> history = repository.findAllByClientUUIDAndMessageID(
|
||||||
|
historyRequestModel.getClientUUID().toString(),
|
||||||
|
historyRequestModel.getMockedResponseId()
|
||||||
|
);
|
||||||
|
Collections.sort(history);
|
||||||
|
|
||||||
|
return history.stream()
|
||||||
|
.filter( historyRecord -> historyRecord
|
||||||
|
.getDateTimeStamp()
|
||||||
|
.isAfter(historyRequestModel.getLocalDateTimeFrom())
|
||||||
|
).filter(
|
||||||
|
historyRecord-> historyRecord
|
||||||
|
.getDateTimeStamp()
|
||||||
|
.isBefore(historyRequestModel.getLocalDateTimeTo())
|
||||||
|
)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveRequest(RequestHistoryDTO requestDTO) {
|
||||||
|
repository.save(requestMapper.requestHistoryDTOToRequestHistory(requestDTO));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
package com.r11.tools.utilis;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enum of keys for redis database.
|
|
||||||
* @author Rafał Żukowicz
|
|
||||||
*/
|
|
||||||
@AllArgsConstructor
|
|
||||||
public enum BusinessKey {
|
|
||||||
INTERFACE_NAME("interfaceName"),
|
|
||||||
CLIENT_UUID("clientUUID"),
|
|
||||||
MESSAGE_ID("messageId");
|
|
||||||
|
|
||||||
private final String phrase;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns string value of given enum variant
|
|
||||||
* @return string value of enum
|
|
||||||
*/
|
|
||||||
public String getReasonPhrase() {
|
|
||||||
return this.phrase;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,235 +0,0 @@
|
|||||||
package com.r11.tools.utilis;
|
|
||||||
|
|
||||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
|
||||||
import ch.qos.logback.core.Layout;
|
|
||||||
import ch.qos.logback.core.UnsynchronizedAppenderBase;
|
|
||||||
import com.cwbase.logback.AdditionalField;
|
|
||||||
import com.cwbase.logback.JSONEventLayout;
|
|
||||||
import java.time.LocalDate;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
|
|
||||||
import redis.clients.jedis.Jedis;
|
|
||||||
import redis.clients.jedis.JedisPool;
|
|
||||||
import redis.clients.jedis.Protocol;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class is used to insert logs directly to Redis. {@link com.release11.klaus.repository.EventRepositoryImpl} is using those logs.
|
|
||||||
* @author Rafał Żukowicz
|
|
||||||
* @author Gabriel Modzelewski
|
|
||||||
*/
|
|
||||||
public class RedisAppender extends UnsynchronizedAppenderBase<ILoggingEvent> {
|
|
||||||
|
|
||||||
JedisPool pool;
|
|
||||||
JSONEventLayout jsonlayout;
|
|
||||||
Layout<ILoggingEvent> layout;
|
|
||||||
String host = "localhost";
|
|
||||||
int port = Protocol.DEFAULT_PORT;
|
|
||||||
String key = null;
|
|
||||||
int timeout = Protocol.DEFAULT_TIMEOUT;
|
|
||||||
String password = null;
|
|
||||||
int database = Protocol.DEFAULT_DATABASE;
|
|
||||||
|
|
||||||
public static final String LOG_PREFIX = "logstash_";
|
|
||||||
|
|
||||||
|
|
||||||
public RedisAppender() {
|
|
||||||
jsonlayout = new JSONEventLayout();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Appends JedisPool by another log
|
|
||||||
* @param event object containing log info
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void append(ILoggingEvent event) {
|
|
||||||
Jedis client = pool.getResource();
|
|
||||||
try {
|
|
||||||
String json = layout == null ? jsonlayout.doLayout(event) : layout.doLayout(event);
|
|
||||||
key = LOG_PREFIX + LocalDate.now();
|
|
||||||
client.rpush(key, json);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} finally {
|
|
||||||
if (client != null) {
|
|
||||||
client.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public String getSource() {
|
|
||||||
return jsonlayout.getSource();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public void setSource(String source) {
|
|
||||||
jsonlayout.setSource(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public String getSourceHost() {
|
|
||||||
return jsonlayout.getSourceHost();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public void setSourceHost(String sourceHost) {
|
|
||||||
jsonlayout.setSourceHost(sourceHost);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public String getSourcePath() {
|
|
||||||
return jsonlayout.getSourcePath();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public void setSourcePath(String sourcePath) {
|
|
||||||
jsonlayout.setSourcePath(sourcePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public String getTags() {
|
|
||||||
if (jsonlayout.getTags() != null) {
|
|
||||||
Iterator<String> i = jsonlayout.getTags().iterator();
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
while (i.hasNext()) {
|
|
||||||
sb.append(i.next());
|
|
||||||
if (i.hasNext()) {
|
|
||||||
sb.append(',');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public void setTags(String tags) {
|
|
||||||
if (tags != null) {
|
|
||||||
String[] atags = tags.split(",");
|
|
||||||
jsonlayout.setTags(Arrays.asList(atags));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public String getType() {
|
|
||||||
return jsonlayout.getType();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public void setType(String type) {
|
|
||||||
jsonlayout.setType(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getHost() {
|
|
||||||
return host;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setHost(String host) {
|
|
||||||
this.host = host;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getPort() {
|
|
||||||
return port;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPort(int port) {
|
|
||||||
this.port = port;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getKey() {
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setKey(String key) {
|
|
||||||
this.key = key;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getTimeout() {
|
|
||||||
return timeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTimeout(int timeout) {
|
|
||||||
this.timeout = timeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPassword() {
|
|
||||||
return password;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPassword(String password) {
|
|
||||||
this.password = password;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getDatabase() {
|
|
||||||
return database;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDatabase(int database) {
|
|
||||||
this.database = database;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public void setMdc(boolean flag) {
|
|
||||||
jsonlayout.setProperties(flag);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public boolean getMdc() {
|
|
||||||
return jsonlayout.getProperties();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public void setLocation(boolean flag) {
|
|
||||||
jsonlayout.setLocationInfo(flag);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public boolean getLocation() {
|
|
||||||
return jsonlayout.getLocationInfo();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public void setCallerStackIndex(int index) {
|
|
||||||
jsonlayout.setCallerStackIdx(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public int getCallerStackIndex() {
|
|
||||||
return jsonlayout.getCallerStackIdx();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public void addAdditionalField(AdditionalField p) {
|
|
||||||
jsonlayout.addAdditionalField(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Layout<ILoggingEvent> getLayout() {
|
|
||||||
return layout;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLayout(Layout<ILoggingEvent> layout) {
|
|
||||||
this.layout = layout;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts new instance of JedisPool
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void start() {
|
|
||||||
super.start();
|
|
||||||
GenericObjectPoolConfig config = new GenericObjectPoolConfig();
|
|
||||||
config.setTestOnBorrow(true);
|
|
||||||
pool = new JedisPool(config, host, port, timeout, password, database);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stops and destroys JedisPool object
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void stop() {
|
|
||||||
super.stop();
|
|
||||||
pool.destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
package com.r11.tools.utilis;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
import org.slf4j.MDC;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This static class has one purpose and one purpose only. It logs data about incomming requests.
|
|
||||||
* The data from logs is received via {@link com.release11.klaus.repository.EventRepositoryImpl}
|
|
||||||
* @author Rafał Żukowski
|
|
||||||
*/
|
|
||||||
public final class TrackingClient {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Logs data inside the given map
|
|
||||||
* @param businessKeysMap map containing all the information about incomming request
|
|
||||||
*/
|
|
||||||
public static void setBusinessKeys(Map<BusinessKey, String> businessKeysMap){
|
|
||||||
for (Map.Entry<BusinessKey, String> entry : businessKeysMap.entrySet()) {
|
|
||||||
MDC.put(entry.getKey().getReasonPhrase(), entry.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -5,3 +5,12 @@ spring.mvc.view.suffix=.html
|
|||||||
logging.level.root=INFO
|
logging.level.root=INFO
|
||||||
logging.level.org.springframework.web=INFO
|
logging.level.org.springframework.web=INFO
|
||||||
logging.level.com.release11=INFO
|
logging.level.com.release11=INFO
|
||||||
|
|
||||||
|
#database:
|
||||||
|
spring.redis.host=redis
|
||||||
|
spring.redis.port=6379
|
||||||
|
|
||||||
|
#retention
|
||||||
|
retention.minutes-to-delete-message=120
|
||||||
|
retention.minutes-to-delete-history-record=1440
|
||||||
|
retention.retention-cooldown=1440
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
redis.host = redis
|
|
||||||
redis.port = 6379
|
|
||||||
@@ -2,25 +2,8 @@
|
|||||||
<configuration>
|
<configuration>
|
||||||
<include resource="org/springframework/boot/logging/logback/base.xml"/>
|
<include resource="org/springframework/boot/logging/logback/base.xml"/>
|
||||||
<property name="HOME_LOG" value="/log/mockServices.log"/>
|
<property name="HOME_LOG" value="/log/mockServices.log"/>
|
||||||
<!--https://github.com/kmtong/logback-redis-appender-->
|
|
||||||
<appender name="LOGSTASH" class="com.r11.tools.utilis.RedisAppender">
|
|
||||||
<host>redis</host>
|
|
||||||
<port>6379</port>
|
|
||||||
<key>logstash</key>
|
|
||||||
<layout class="ch.qos.logback.classic.PatternLayout">
|
|
||||||
<!--https://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html-->
|
|
||||||
<Pattern>
|
|
||||||
{"dateTimeStamp" : "%d{yyyy-MM-dd}T%d{HH:mm:ss}", "eventId":"%X{eventId}", "interfaceName":"%X{interfaceName}", "clientUUID":"%X{clientUUID}", "messageId":"%X{messageId}", "thread":"%t","level":"%-5level", "message":"%msg"}%n
|
|
||||||
</Pattern>
|
|
||||||
</layout>
|
|
||||||
</appender>
|
|
||||||
<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
|
|
||||||
<appender-ref ref="LOGSTASH" />
|
|
||||||
</appender>
|
|
||||||
|
|
||||||
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
<file>${HOME_LOG}</file>
|
<file>${HOME_LOG}</file>
|
||||||
|
|
||||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||||
<fileNamePattern>logs/mockServices.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
|
<fileNamePattern>logs/mockServices.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
|
||||||
<maxFileSize>10MB</maxFileSize>
|
<maxFileSize>10MB</maxFileSize>
|
||||||
@@ -34,7 +17,6 @@
|
|||||||
</appender>
|
</appender>
|
||||||
|
|
||||||
<root level="DEBUG">
|
<root level="DEBUG">
|
||||||
<appender-ref ref="ASYNC" />
|
|
||||||
<appender-ref ref="CONSOLE" />
|
<appender-ref ref="CONSOLE" />
|
||||||
<appender-ref ref="FILE" />
|
<appender-ref ref="FILE" />
|
||||||
</root>
|
</root>
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
@import url('r11tooltip.css');
|
@import url('r11tooltip.css');
|
||||||
@import url('r11modal.css');
|
@import url('r11modal.css');
|
||||||
@import url('r11flexbox.css');
|
@import url('r11flexbox.css');
|
||||||
|
@import url('r11popup.css');
|
||||||
|
@import url('../../highlight.css');
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Material Icons';
|
font-family: 'Material Icons';
|
||||||
|
|||||||
@@ -69,4 +69,27 @@
|
|||||||
.content p {
|
.content p {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.refresh-button{
|
||||||
|
float: right;
|
||||||
|
border: none;
|
||||||
|
background-color: unset;
|
||||||
|
font-size: xx-large;
|
||||||
|
}
|
||||||
|
|
||||||
|
.refresh-button:hover{
|
||||||
|
animation-name: rotation;
|
||||||
|
animation-duration: 0.8s;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes rotation{
|
||||||
|
from{
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
83
Frontend/assets/css/tools/mock/r11popup.css
Normal file
83
Frontend/assets/css/tools/mock/r11popup.css
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
.popup-flex:not(.hiddable-container){
|
||||||
|
animation: blur 0.5s ease-in-out ;
|
||||||
|
animation-fill-mode: forwards;
|
||||||
|
}
|
||||||
|
.popup-flex{
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: 50;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2%;
|
||||||
|
position: fixed;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-body{
|
||||||
|
min-width: 33%;
|
||||||
|
max-width: 60%;
|
||||||
|
max-height: 70%;
|
||||||
|
background-color: white;
|
||||||
|
box-shadow: 10px 10px 5px lightblue;
|
||||||
|
min-height: 45%;
|
||||||
|
border-radius: 1em;
|
||||||
|
text-align: center;
|
||||||
|
padding: 10px 15px 15px 15px;
|
||||||
|
color: black;
|
||||||
|
border: 1px #2A93B0 solid;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
position: fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-button-close-container{
|
||||||
|
text-align: right;
|
||||||
|
margin-right: 2%;
|
||||||
|
margin-top: 1%;
|
||||||
|
font-size: xx-large;
|
||||||
|
font-weight: bold;
|
||||||
|
position: sticky;
|
||||||
|
top:0
|
||||||
|
}
|
||||||
|
|
||||||
|
.hiddable-popup-option{
|
||||||
|
flex-grow: 1;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 1.5%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-button-close{
|
||||||
|
background: padding-box;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-button-close:hover{
|
||||||
|
color: #2A93B0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hiddable-container{
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden-popup-type{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#history-request-body{
|
||||||
|
text-align: justify;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes blur {
|
||||||
|
0% {
|
||||||
|
backdrop-filter: blur(0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
backdrop-filter: blur(5px);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -68,4 +68,29 @@
|
|||||||
background-color: #3bc4f1;
|
background-color: #3bc4f1;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
color: white;
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-default td{
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#header-table tr td {
|
||||||
|
border: 1px black solid;
|
||||||
|
padding: 1.5%;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#header-table{
|
||||||
|
border-collapse: collapse;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-header-name{
|
||||||
|
min-width: 10vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
#historyTable, td{
|
||||||
|
padding: 1%;
|
||||||
|
overflow-x: scroll;
|
||||||
}
|
}
|
||||||
@@ -470,7 +470,7 @@ function selectMessage(id){
|
|||||||
$('.tile[tileid="'+id+'"]').addClass("active");
|
$('.tile[tileid="'+id+'"]').addClass("active");
|
||||||
|
|
||||||
initializeHistory();
|
initializeHistory();
|
||||||
refreshHeaderTable(innerHTML);
|
refreshHeaderTable(document.innerHTML);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -46,13 +46,36 @@ function historyToHtml(){
|
|||||||
for(let i=0; i<iterations; i++){
|
for(let i=0; i<iterations; i++){
|
||||||
let style = i%2==0 ? ' class="even"' : '';
|
let style = i%2==0 ? ' class="even"' : '';
|
||||||
innerHTML += '<tr' + style + '>' +
|
innerHTML += '<tr' + style + '>' +
|
||||||
'<td>' + historyJson[i].dateTimeStamp + '</td>' +
|
'<td>' + parseTimeStamp(historyJson[i].dateTimeStamp) + '</td>' +
|
||||||
'<td>' + historyJson[i].interfaceName + '</td>' +
|
'<td>' + historyJson[i].httpMethod + '</td>' +
|
||||||
|
'<td>' + parseRequestBody(historyJson[i].requestBody, i) + '</td>' +
|
||||||
|
'<td> <button id="'+i+'" class="showHeaderButton" onClick="showHeadersHistory(this);"> Show headers </button> </td>' +
|
||||||
'</tr>';
|
'</tr>';
|
||||||
}
|
}
|
||||||
return innerHTML;
|
return innerHTML;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function parseRequestBody(requestBody,i){
|
||||||
|
return requestBody.length == 0 ?
|
||||||
|
"No request body" :
|
||||||
|
'<button id="'+i+'" class="showRequestBodyButton" onClick="showRequestBody(this);"> Show request body </button>'
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseTimeStamp(timeStamp){
|
||||||
|
return timeStamp.substring(0,19).replace('T',' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseHeaders(pos){
|
||||||
|
parsedJson = new Map();
|
||||||
|
headers = historyJson[pos].headers
|
||||||
|
Object.keys( headers ).forEach(
|
||||||
|
(jsonKey) => {
|
||||||
|
parsedJson.set( jsonKey , headers[jsonKey] );
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return parsedJson;
|
||||||
|
}
|
||||||
|
|
||||||
function displayHistory(){
|
function displayHistory(){
|
||||||
$('#historyTable tbody').html(historyToHtml());
|
$('#historyTable tbody').html(historyToHtml());
|
||||||
}
|
}
|
||||||
|
|||||||
34
Frontend/assets/scripts/tools/mock/popup.js
Normal file
34
Frontend/assets/scripts/tools/mock/popup.js
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
|
||||||
|
function switchPopups (neededPopupOption) {
|
||||||
|
$('.hiddable-popup-option').addClass('hidden-popup-type');
|
||||||
|
$('#'+neededPopupOption).removeClass('hidden-popup-type');
|
||||||
|
}
|
||||||
|
|
||||||
|
function showPopup(){
|
||||||
|
$('.popup-flex').removeClass('hiddable-container');
|
||||||
|
}
|
||||||
|
|
||||||
|
function hidePopup(){
|
||||||
|
$('.popup-flex').addClass('hiddable-container');
|
||||||
|
$('.hiddable-popup-option').addClass('hidden-popup-type');
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Event listener that's close the popup when user clicks out of a popup.
|
||||||
|
*/
|
||||||
|
|
||||||
|
window.addEventListener(
|
||||||
|
'click' ,
|
||||||
|
(clickedElement) => {
|
||||||
|
if(!document.getElementById('popup-body').contains(clickedElement.target) && clickedElement.target.className == 'popup-flex' ) {
|
||||||
|
hidePopup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
$('.popup-button-close').click(
|
||||||
|
() => {
|
||||||
|
hidePopup();
|
||||||
|
$('.hiddable-popup-option').addClass('hidden-popup-type')
|
||||||
|
}
|
||||||
|
);
|
||||||
@@ -35,7 +35,6 @@ $('#historyTab').click(showHistory);
|
|||||||
$('#btn-history-filter').click(historyFilterSwitch);
|
$('#btn-history-filter').click(historyFilterSwitch);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const tabitem = $('.tabitem');
|
const tabitem = $('.tabitem');
|
||||||
function showHistory(){
|
function showHistory(){
|
||||||
$('#headersTab').click(showHeaders);
|
$('#headersTab').click(showHeaders);
|
||||||
@@ -52,8 +51,6 @@ function initializeHistory(){
|
|||||||
getLast24hHistoryData();
|
getLast24hHistoryData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function showHeaders(){
|
function showHeaders(){
|
||||||
$('#historyTab').click(showHistory);
|
$('#historyTab').click(showHistory);
|
||||||
tabitem.removeClass('active');
|
tabitem.removeClass('active');
|
||||||
@@ -63,6 +60,109 @@ function showHeaders(){
|
|||||||
$('#headersTab').off('click');
|
$('#headersTab').off('click');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showHeadersHistory(element){
|
||||||
|
historyTable = '';
|
||||||
|
headers = parseHeaders(element.id)
|
||||||
|
headers.forEach(
|
||||||
|
(value,key) => {
|
||||||
|
historyTable +=
|
||||||
|
'<tr>' +
|
||||||
|
'<td class="history-header-name">'+ key + '</td>' +
|
||||||
|
'<td class="history-header-value">'+ value + '</td>' +
|
||||||
|
'</tr>'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
document.getElementById('header-history-table-body').innerHTML = historyTable;
|
||||||
|
switchPopups('history-headers-table');
|
||||||
|
showPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function formatJSON(json) {
|
||||||
|
const address = window.location.protocol + "//" + window.location.hostname + ":" + 8081 + "/json/formatting";
|
||||||
|
|
||||||
|
var init = {
|
||||||
|
body: json,
|
||||||
|
method: "POST"
|
||||||
|
};
|
||||||
|
var request = new Request(address, init);
|
||||||
|
|
||||||
|
var result = await fetch(request).then(response => {
|
||||||
|
return response.text().then(function (text) {
|
||||||
|
var json = JSON.parse(text);
|
||||||
|
json.status = response.status;
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function formatXML(xml) {
|
||||||
|
const address = window.location.protocol + "//" + window.location.hostname + ":" + 8082 + "/prettify";
|
||||||
|
var data = {
|
||||||
|
data: xml,
|
||||||
|
process: "",
|
||||||
|
processor: "libxml",
|
||||||
|
version: "1.0"
|
||||||
|
}
|
||||||
|
|
||||||
|
var init = {
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
method: "POST"
|
||||||
|
};
|
||||||
|
var request = new Request(address, init);
|
||||||
|
|
||||||
|
var result = await fetch(request).then(response => {
|
||||||
|
return response.text().then(function (text) {
|
||||||
|
return JSON.parse(text);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function showRequestBody(element){
|
||||||
|
var historyRequestBody = historyJson[element.id].requestBody;
|
||||||
|
const popupContent = document.getElementById('code-highlight-content')
|
||||||
|
|
||||||
|
document.getElementById('code-highlight-content').innerText = "Loading...";
|
||||||
|
switch(historyJson[element.id].headers["content-type"]){
|
||||||
|
case "application/json":{
|
||||||
|
formatJSON(historyRequestBody).then(function(result) {
|
||||||
|
|
||||||
|
if (result.status == "200") {
|
||||||
|
popupContent.innerText = result.data;
|
||||||
|
highlightSyntax('code-highlight-content');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
popupContent.innerText = historyRequestBody;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "application/xml":{
|
||||||
|
formatXML(historyRequestBody).then(function(result) {
|
||||||
|
if (result.status == "OK") {
|
||||||
|
popupContent.innerText = result.result;
|
||||||
|
highlightSyntax('code-highlight-content');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
popupContent.innerText = historyRequestBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:{
|
||||||
|
popupContent.innerText = historyRequestBody;
|
||||||
|
highlightSyntax('code-highlight-content');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switchPopups('history-request-body');
|
||||||
|
showPopup();
|
||||||
|
}
|
||||||
|
|
||||||
function focusInTip(element){
|
function focusInTip(element){
|
||||||
showTip(element);
|
showTip(element);
|
||||||
focusedField = true;
|
focusedField = true;
|
||||||
@@ -73,6 +173,10 @@ function focusOutTip(element){
|
|||||||
hidTip(element);
|
hidTip(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function refreshHistoryRecords(){
|
||||||
|
getLast24hHistoryData();
|
||||||
|
}
|
||||||
|
|
||||||
function hidTip(element){
|
function hidTip(element){
|
||||||
if(focusedField) return;
|
if(focusedField) return;
|
||||||
$('#'+element).removeClass('active');
|
$('#'+element).removeClass('active');
|
||||||
|
|||||||
@@ -9,6 +9,34 @@
|
|||||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<div class="popup-flex hiddable-container">
|
||||||
|
<div class="popup-body" id="popup-body">
|
||||||
|
<div class="popup-button-close-container">
|
||||||
|
<button type="button" class="popup-button-close"> X </button>
|
||||||
|
</div>
|
||||||
|
<div class="popup-header-table hiddable-popup-option" id="history-headers-table">
|
||||||
|
<table id="header-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
Header Name
|
||||||
|
</th>
|
||||||
|
|
||||||
|
<th>
|
||||||
|
Header Value
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="header-history-table-body">
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="popup-request-body hiddable-popup-option" id="history-request-body">
|
||||||
|
<pre class="code-content" id="history-request-body-content"><code id="code-highlight-content"></code></pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="tool extended">
|
<div class="tool extended">
|
||||||
<div class="tool-context">
|
<div class="tool-context">
|
||||||
@@ -127,7 +155,10 @@
|
|||||||
<!-- history -->
|
<!-- history -->
|
||||||
<div id="history" class="medium-vertical-margin tabcontent">
|
<div id="history" class="medium-vertical-margin tabcontent">
|
||||||
<div class="block-display max-width">
|
<div class="block-display max-width">
|
||||||
<button id="btn-history-filter" class="clickable-text highlight switch"><span class="toggleIndicator"></span> filter</button>
|
<button id="btn-history-filter" class="clickable-text highlight switch">
|
||||||
|
<span class="toggleIndicator"></span> filter
|
||||||
|
<button type="button" class="refresh-button" onclick="refreshHistoryRecords();" >↻</button>
|
||||||
|
</button>
|
||||||
<div id ="history-filter" class="display-space-between max-width small-vertical-margin hiddable">
|
<div id ="history-filter" class="display-space-between max-width small-vertical-margin hiddable">
|
||||||
<div class="three-fourth-width display-space-evenly">
|
<div class="three-fourth-width display-space-evenly">
|
||||||
<div class="block-display half-width with-padding">
|
<div class="block-display half-width with-padding">
|
||||||
@@ -149,7 +180,9 @@
|
|||||||
<thead>
|
<thead>
|
||||||
<tr class="bottom-border">
|
<tr class="bottom-border">
|
||||||
<th>Timestamp</th>
|
<th>Timestamp</th>
|
||||||
<th>Type</th>
|
<th>Method</th>
|
||||||
|
<th>Request Body</th>
|
||||||
|
<th>Headers</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@@ -299,5 +332,9 @@
|
|||||||
<script type="text/javascript" src="../assets/scripts/tools/mock/datatransfer.js"></script>
|
<script type="text/javascript" src="../assets/scripts/tools/mock/datatransfer.js"></script>
|
||||||
<script type="text/javascript" src="../assets/scripts/tools/mock/historyloader.js"></script>
|
<script type="text/javascript" src="../assets/scripts/tools/mock/historyloader.js"></script>
|
||||||
<script type="text/javascript" src="../assets/scripts/tools/mock/fiddle.js"></script>
|
<script type="text/javascript" src="../assets/scripts/tools/mock/fiddle.js"></script>
|
||||||
|
<script type="text/javascript" src="../assets/scripts/tools/mock/popup.js"></script>
|
||||||
|
<script type="text/javascript" src="../assets/scripts/tools/xmlFormatter.js"></script>
|
||||||
|
<script type="text/javascript" src="../assets/scripts/tools/highlight.js"></script>
|
||||||
|
<script type="text/javascript" src="../assets/scripts/common/hljs.min.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user