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> | ||||
|     <groupId>org.springframework.boot</groupId> | ||||
|     <artifactId>spring-boot-starter-parent</artifactId> | ||||
|     <version>2.3.1.RELEASE</version> | ||||
|     <version>2.7.11</version> | ||||
|     <relativePath/> <!-- lookup parent from repository --> | ||||
|   </parent> | ||||
|  | ||||
| @@ -18,9 +18,10 @@ | ||||
|     <jedis.version>3.3.0</jedis.version> | ||||
|     <logback-redis-appender.version>1.1.6</logback-redis-appender.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.name>${project.artifactId}</docker.image.name> | ||||
|     <lombok.version>1.18.26</lombok.version> | ||||
|   </properties> | ||||
|  | ||||
|   <dependencies> | ||||
| @@ -57,21 +58,6 @@ | ||||
|       <groupId>org.springframework.boot</groupId> | ||||
|       <artifactId>spring-boot-starter-data-redis</artifactId> | ||||
|     </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> | ||||
|  | ||||
|   <build> | ||||
| @@ -101,6 +87,11 @@ | ||||
|               <artifactId>lombok</artifactId> | ||||
|               <version>${lombok.version}</version> | ||||
|             </path> | ||||
|             <dependency> | ||||
|               <groupId>org.projectlombok</groupId> | ||||
|               <artifactId>lombok-mapstruct-binding</artifactId> | ||||
|               <version>0.2.0</version> | ||||
|             </dependency> | ||||
|           </annotationProcessorPaths> | ||||
|           <compilerArgs> | ||||
|             <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.r11.tools.model.MockedMessageDto; | ||||
| import com.r11.tools.service.KlausService; | ||||
| import com.r11.tools.utilis.BusinessKey; | ||||
| import com.r11.tools.utilis.TrackingClient; | ||||
| import lombok.AllArgsConstructor; | ||||
| import lombok.SneakyThrows; | ||||
| import org.apache.logging.log4j.LogManager; | ||||
| 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 java.time.LocalDateTime; | ||||
| @@ -18,17 +19,19 @@ import java.util.*; | ||||
| /** | ||||
|  * Returns the homepage and provides the api for javascript async requests. | ||||
|  * @author Gabriel Modzelewski | ||||
|  * @author Mikołaj Widła | ||||
|  */ | ||||
| @RestController | ||||
| @RequestMapping(path = "/api/mock") | ||||
| @AllArgsConstructor | ||||
| @CrossOrigin(origins = "*") | ||||
| public class MockController { | ||||
|     private final KlausService klausService; | ||||
|     private final Logger log = LogManager.getRootLogger(); | ||||
|  | ||||
|     @ExceptionHandler(Exception.class) | ||||
|     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 | ||||
|      * 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 mockedResponseId unique id of given message | ||||
|      * @return | ||||
|      */ | ||||
|     @GetMapping(value = "/r/{clientUUID}/{mockedResponseId}") | ||||
|     public ResponseEntity getMockedResponse(RequestEntity<String> requestEntity, | ||||
|     @RequestMapping(value = "/r/{clientUUID}/{mockedResponseId}") | ||||
|     public ResponseEntity getMockedResponse( | ||||
|                                             @PathVariable UUID clientUUID, | ||||
|                                             @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); | ||||
|         HttpHeaders httpHeaders = new HttpHeaders(); | ||||
|         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.validation.BindException; | ||||
| import org.springframework.web.bind.annotation.ControllerAdvice; | ||||
| import org.springframework.web.bind.annotation.CrossOrigin; | ||||
| import org.springframework.web.bind.annotation.ExceptionHandler; | ||||
|  | ||||
|  | ||||
| @@ -15,6 +16,7 @@ import org.springframework.web.bind.annotation.ExceptionHandler; | ||||
|  * @author Rafał Żukowicz | ||||
|  */ | ||||
| @ControllerAdvice | ||||
| @CrossOrigin(origins = "*") | ||||
| 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 { | ||||
|     @Mapping( target = "compositePrimaryKey", expression = "java(mockedMessageDto.getClientUUID() + \"_\"" + | ||||
|             " + mockedMessageDto.getMockedResponseId())") | ||||
|     @Mapping( target = "createdAt" , expression = "java(java.time.LocalDateTime.now())") | ||||
|     MockedMessage mockedMessageDtoToMockedMessage(MockedMessageDto mockedMessageDto); | ||||
|     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; | ||||
| 
 | ||||
| import java.time.LocalDateTime; | ||||
| import java.util.UUID; | ||||
| import lombok.AllArgsConstructor; | ||||
| import lombok.Builder; | ||||
| import lombok.Data; | ||||
| import lombok.NoArgsConstructor; | ||||
| 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 | ||||
|  * @author Rafał Żukowicz | ||||
|  * Represents all data needed to get HistoryRecord from database | ||||
|  * @author Mikołaj Widła | ||||
|  */ | ||||
| 
 | ||||
| @Data | ||||
| @Builder | ||||
| @NoArgsConstructor | ||||
| @AllArgsConstructor | ||||
| public class EventRequestDto { | ||||
| public class HistoryRequestModel { | ||||
| 
 | ||||
|     private UUID clientUUID; | ||||
|     @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) | ||||
| @@ -2,6 +2,7 @@ package com.r11.tools.model; | ||||
|  | ||||
| import com.r11.tools.model.constraints.HttpCode; | ||||
| import java.io.Serializable; | ||||
| import java.time.LocalDateTime; | ||||
| import java.util.Map; | ||||
| import java.util.UUID; | ||||
| import javax.validation.constraints.Positive; | ||||
| @@ -34,6 +35,7 @@ public class MockedMessage implements Serializable { | ||||
|     private Map<String, String> httpHeaders; | ||||
|     @HttpCode | ||||
|     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; | ||||
|  | ||||
| import com.fasterxml.jackson.databind.ObjectMapper; | ||||
| import com.r11.tools.mappers.MockedMessageMapper; | ||||
| import com.r11.tools.model.MockedMessage; | ||||
| import com.r11.tools.model.MockedMessageDto; | ||||
| @@ -13,6 +12,7 @@ import org.springframework.http.HttpHeaders; | ||||
| import org.springframework.http.HttpStatus; | ||||
| import org.springframework.http.ResponseEntity; | ||||
| import org.springframework.stereotype.Service; | ||||
|  | ||||
| import java.util.List; | ||||
| import java.util.Optional; | ||||
| import java.util.UUID; | ||||
| @@ -30,7 +30,6 @@ public class KlausServiceImpl implements KlausService { | ||||
|     private final MockedMessageMapper mockedMessageMapper; | ||||
|     private final Logger log = LogManager.getRootLogger(); | ||||
|     private final MockedResponseRepository mockedResponseRepository; | ||||
|     private final ObjectMapper objectMapper; | ||||
|  | ||||
|     /** | ||||
|      * 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.org.springframework.web=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> | ||||
|     <include resource="org/springframework/boot/logging/logback/base.xml"/> | ||||
|     <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"> | ||||
|         <file>${HOME_LOG}</file> | ||||
|  | ||||
|         <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> | ||||
|             <fileNamePattern>logs/mockServices.%d{yyyy-MM-dd}.%i.log</fileNamePattern> | ||||
|             <maxFileSize>10MB</maxFileSize> | ||||
| @@ -34,7 +17,6 @@ | ||||
|     </appender> | ||||
|  | ||||
|     <root level="DEBUG"> | ||||
|         <appender-ref ref="ASYNC" /> | ||||
|         <appender-ref ref="CONSOLE" /> | ||||
|         <appender-ref ref="FILE" /> | ||||
|     </root> | ||||
|   | ||||
| @@ -6,6 +6,8 @@ | ||||
| @import url('r11tooltip.css'); | ||||
| @import url('r11modal.css'); | ||||
| @import url('r11flexbox.css'); | ||||
| @import url('r11popup.css'); | ||||
| @import url('../../highlight.css'); | ||||
|  | ||||
| @font-face { | ||||
|     font-family: 'Material Icons'; | ||||
|   | ||||
| @@ -70,3 +70,26 @@ | ||||
|     margin: 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); | ||||
|     } | ||||
|   } | ||||
| @@ -69,3 +69,28 @@ | ||||
|     text-align: left; | ||||
|     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"); | ||||
|      | ||||
|     initializeHistory(); | ||||
|     refreshHeaderTable(innerHTML); | ||||
|     refreshHeaderTable(document.innerHTML); | ||||
| } | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -46,13 +46,36 @@ function historyToHtml(){ | ||||
|     for(let i=0; i<iterations; i++){ | ||||
|         let style = i%2==0 ? ' class="even"' : ''; | ||||
|         innerHTML += '<tr' + style + '>' + | ||||
|             '<td>' + historyJson[i].dateTimeStamp + '</td>' + | ||||
|             '<td>' + historyJson[i].interfaceName + '</td>' + | ||||
|             '<td>' + parseTimeStamp(historyJson[i].dateTimeStamp) + '</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>'; | ||||
|     } | ||||
|     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(){ | ||||
|     $('#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); | ||||
|  | ||||
|  | ||||
|  | ||||
| const tabitem = $('.tabitem'); | ||||
| function showHistory(){ | ||||
|     $('#headersTab').click(showHeaders); | ||||
| @@ -52,8 +51,6 @@ function initializeHistory(){ | ||||
|     getLast24hHistoryData(); | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| function showHeaders(){ | ||||
|     $('#historyTab').click(showHistory); | ||||
|     tabitem.removeClass('active'); | ||||
| @@ -63,6 +60,109 @@ function showHeaders(){ | ||||
|     $('#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){ | ||||
|     showTip(element); | ||||
|     focusedField = true; | ||||
| @@ -73,6 +173,10 @@ function focusOutTip(element){ | ||||
|     hidTip(element); | ||||
| } | ||||
|  | ||||
| function refreshHistoryRecords(){ | ||||
|     getLast24hHistoryData(); | ||||
| } | ||||
|  | ||||
| function hidTip(element){ | ||||
|     if(focusedField) return; | ||||
|     $('#'+element).removeClass('active'); | ||||
|   | ||||
| @@ -9,6 +9,34 @@ | ||||
|     <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> | ||||
| </head> | ||||
| <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="tool extended"> | ||||
|             <div class="tool-context"> | ||||
| @@ -127,7 +155,10 @@ | ||||
|                             <!-- history --> | ||||
|                             <div id="history" class="medium-vertical-margin tabcontent"> | ||||
|                                 <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 class="three-fourth-width display-space-evenly"> | ||||
|                                             <div class="block-display half-width with-padding"> | ||||
| @@ -149,7 +180,9 @@ | ||||
|                                             <thead> | ||||
|                                                 <tr class="bottom-border"> | ||||
|                                                     <th>Timestamp</th> | ||||
|                                                     <th>Type</th> | ||||
|                                                     <th>Method</th> | ||||
|                                                     <th>Request Body</th> | ||||
|                                                     <th>Headers</th> | ||||
|                                                 </tr> | ||||
|                                             </thead> | ||||
|                                             <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/historyloader.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> | ||||
| </html> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user