Changed Homepage to Frontend and fixed typo

This commit is contained in:
2023-01-16 13:59:06 +01:00
parent 5655e46112
commit 8f4e42c533
92 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,18 @@
package com.r11.tools;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* It's generic Spring context starter. Move along...
*
* @author Rafał Żukowicz
*/
@SpringBootApplication
public class KlausApplication {
public static void main(String[] args) {
SpringApplication.run(KlausApplication.class, args);
}
}

View File

@@ -0,0 +1,68 @@
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;
}
}

View File

@@ -0,0 +1,22 @@
package com.r11.tools.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration
@EnableSwagger2
public class SpringFoxConfig {
@Bean
public Docket api(){
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.ant("/api/**"))
.build();
}
}

View File

@@ -0,0 +1,58 @@
package com.r11.tools.controller;
import com.r11.tools.model.EventRequestDto;
import com.r11.tools.service.EtrackService;
import java.time.LocalDateTime;
import java.util.UUID;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
/**
* It's the REST api for {@link com.r11.tools.model.Event}
* @author Gabriel Modzelewski
*/
@Slf4j
@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);
}
}

View File

@@ -0,0 +1,27 @@
package com.r11.tools.controller;
import lombok.SneakyThrows;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
/**
* Class responsible for returning homepage html
* @author Gabriel Modzelewski
*/
@Controller
@RequestMapping("/")
public class MainController {
/**
* Default path to get the homepage
* @return the view of homepage
*/
@SneakyThrows
@GetMapping
public ModelAndView showHome(){
ModelAndView mov = new ModelAndView();
mov.setViewName("html/mock");
return mov;
}
}

View File

@@ -0,0 +1,173 @@
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 java.time.LocalDateTime;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;
/**
* Returns the homepage and provides the api for javascript async requests.
* @author Gabriel Modzelewski
*/
@Slf4j
@RestController
@RequestMapping(path = "/api/mock")
@AllArgsConstructor
public class MockController {
private final KlausService klausService;
/**
* Updates queried message with given set of data
* @param body {@link MockedMessageDto} json representation
* @return confirmation and 200 OK
*/
@SneakyThrows
@PutMapping
public ResponseEntity<String> updateMessage(@RequestBody String body){
ObjectMapper mapper = new ObjectMapper();
MockedMessageDto message = mapper.readValue(body, MockedMessageDto.class);
return klausService.setMockedResponse(message);
}
/**
* Returns the full list of messages. It's used by javascript on the client side to initialize homepage
* with data from the database.
* @param uuidValue the key-uuid of given set of messages
* @return responds with 200 OK and list of {@link MockedMessageDto}
*/
@GetMapping({"/", "/{uuidValue}"})
public List<MockedMessageDto> getListOfMessages(@PathVariable(required = false) String uuidValue){
UUID clientUUID;
if(uuidValue == null || uuidValue.equals("")) clientUUID = UUID.randomUUID();
else clientUUID = UUID.fromString(uuidValue);
List<MockedMessageDto> messages = klausService.getAllMockedResponses(clientUUID);
if(messages.size() == 0) {
klausService.setMockedResponse(buildDefaultMessage(clientUUID));
messages = klausService.getAllMockedResponses(clientUUID);
}
Collections.sort(messages);
return messages;
}
/**
* Accepts empty post request and creates new message in given set. The new message has default set of data,
* which is constructed in {@link #buildDefaultMessage(UUID, int)} method.
* @param uuidValue the key-uuid of given set of messages
* @return confirmation response with 200 OK
*/
@PostMapping("/{uuidValue}")
public ResponseEntity<String> addNewMessage(@PathVariable String uuidValue){
UUID clientUUID = UUID.fromString(uuidValue);
List<MockedMessageDto> messages = klausService.getAllMockedResponses(clientUUID);
MockedMessageDto nextMessage = buildDefaultMessage(clientUUID, findNextId(messages));
return klausService.setMockedResponse(nextMessage);
}
/**
* Deletes message of given id via client request
* @param uuidValue the key-uuid of given set of messages
* @param idValue unique id of given message
* @return after deletion the confirmation is send with status 200 OK
*/
@DeleteMapping("/{uuidValue}/{idValue}")
public ResponseEntity<String> removeMessage(@PathVariable String uuidValue,
@PathVariable String idValue){
UUID clientUUID = UUID.fromString(uuidValue);
int id = Integer.parseInt(idValue);
return klausService.deleteMockedResponse(clientUUID, id);
}
/**
* Recalls {@link #buildDefaultMessage(UUID)} for message construction and sets id of message
* @param uuid the key-uuid of given set of messages
* @param id unique id of given message
* @return message with default dataset and set id
*/
private static MockedMessageDto buildDefaultMessage(UUID uuid, int id){
MockedMessageDto message = buildDefaultMessage(uuid);
message.setMockedResponseId(id);
return message;
}
/**
* Constructs message with default set of data
* @param uuid the key-uuid of given set of messages
* @return message with default dataset
*/
private static MockedMessageDto buildDefaultMessage(UUID uuid){
Map<String, String> headers = new HashMap<>();
headers.put("Keep-Alive", "timeout=60");
headers.put("Connection", "keep-alive");
headers.put("Date", LocalDateTime.now().toString());
return MockedMessageDto.builder()
.clientUUID(uuid)
.mockedResponseId(1)
.mediaType(MediaType.APPLICATION_XML_VALUE)
.messageBody("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<note>\n" +
" <to>Tove</to>\n" +
" <from>Jani</from>\n" +
" <heading>Reminder</heading>\n" +
" <body>Don't forget me this weekend!</body>\n" +
"</note>")
.httpHeaders(headers)
.httpStatus(200)
.build();
}
/**
* Finds the highest id in the list and returns it incremented by 1
* @param messages list of messages
* @return highest id incremented by 1
*/
public static int findNextId(List<MockedMessageDto> messages) {
int highestId = 0;
for (MockedMessageDto m : messages)
highestId = highestId > m.getMockedResponseId() ? highestId : m.getMockedResponseId();
return ++highestId;
}
/**
* 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,
@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));
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);
return new ResponseEntity<>(mockedMessageDto.getMessageBody(), httpHeaders,
Objects.requireNonNull(HttpStatus.valueOf(mockedMessageDto.getHttpStatus())));
}
}

View File

@@ -0,0 +1,47 @@
package com.r11.tools.controller;
import java.util.ArrayList;
import java.util.List;
import javax.validation.ConstraintViolationException;
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.ExceptionHandler;
/**
* Custom exception handler for {@link ConstraintViolationException}
* @author Rafał Żukowicz
*/
@ControllerAdvice
public class MvcExceptionHandler {
/**
* Provides handling for {@link ConstraintViolationException}
* @param e exception argument
* @return response with error list and status 400 bad request
*/
@ExceptionHandler(ConstraintViolationException.class)
public ResponseEntity<List> validationErrorHandler(ConstraintViolationException e){
List<String> errors = new ArrayList<>(e.getConstraintViolations().size());
e.getConstraintViolations().forEach(constraintViolation -> {
errors.add(constraintViolation.getPropertyPath() + " : " + constraintViolation.getMessage());
});
return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST);
}
/**
* Provides handling for {@link BindException}
* @param ex exception argument
* @return response with error list and status 400 bad request
*/
@ExceptionHandler(BindException.class)
public ResponseEntity<List> handleBindException(BindException ex){
return new ResponseEntity(ex.getAllErrors(), HttpStatus.BAD_REQUEST);
}
}

View File

@@ -0,0 +1,17 @@
package com.r11.tools.mappers;
import com.r11.tools.model.MockedMessage;
import com.r11.tools.model.MockedMessageDto;
import org.mapstruct.*;
/**
* Creates key value for redis entry
* @author Rafał Źukowicz
*/
@Mapper
public interface MockedMessageMapper {
@Mapping( target = "compositePrimaryKey", expression = "java(mockedMessageDto.getClientUUID() + \"_\"" +
" + mockedMessageDto.getMockedResponseId())")
MockedMessage mockedMessageDtoToMockedMessage(MockedMessageDto mockedMessageDto);
MockedMessageDto mockedMessageToMockedMessageDto(MockedMessage mockedMessage);
}

View File

@@ -0,0 +1,36 @@
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;
}
}

View File

@@ -0,0 +1,28 @@
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;
/**
* Pojo for history query request. Contains information necessary to obtain {@link Event} list
* @author Rafał Żukowicz
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class EventRequestDto {
private UUID clientUUID;
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
private LocalDateTime localDateTimeFrom;
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
private LocalDateTime localDateTimeTo;
private Integer mockedResponseId;
}

View File

@@ -0,0 +1,40 @@
package com.r11.tools.model;
import com.r11.tools.model.constraints.HttpCode;
import java.io.Serializable;
import java.util.Map;
import java.util.UUID;
import javax.validation.constraints.Positive;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.springframework.data.annotation.Id;
import org.springframework.data.redis.core.RedisHash;
import org.springframework.data.redis.core.index.Indexed;
/**
* MockedMessage redis entity pojo
* @author Rafał Żukowicz
*/
@Data
@ToString
@RedisHash("mockedMessage")
@NoArgsConstructor
@AllArgsConstructor
public class MockedMessage implements Serializable {
@Id
private String compositePrimaryKey;
@Indexed
private UUID clientUUID;
@Positive
private Integer mockedResponseId;
private String mediaType;
private String messageBody;
private Map<String, String> httpHeaders;
@HttpCode
private Integer httpStatus;
}

View File

@@ -0,0 +1,36 @@
package com.r11.tools.model;
import com.r11.tools.model.constraints.HttpCode;
import java.io.Serializable;
import java.util.Map;
import java.util.UUID;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Positive;
import lombok.*;
/**
* Alternative version of {@link MockedMessage} used in http body
* @author Rafał Żukowicz
* @author Gabriel Modzelewski
*/
@Data
@Builder
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class MockedMessageDto implements Serializable, Comparable<MockedMessageDto> {
private UUID clientUUID;
@NotNull
@Positive
private Integer mockedResponseId;
private String mediaType;
private String messageBody;
private Map<String, String> httpHeaders;
@HttpCode
private Integer httpStatus;
@Override
public int compareTo(MockedMessageDto message) {
return this.mockedResponseId > message.getMockedResponseId() ? 1 : -1;
}
}

View File

@@ -0,0 +1,23 @@
package com.r11.tools.model.constraints;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.validation.Constraint;
import javax.validation.Payload;
/**
* Annotation interface that is used to annotate Integer fields that contain http status values.
* It provides validation and throws an error when trying to send response with incorrect status.
* @author Rafał Żukowicz
*/
@Target({ ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = HttpCodeValidation.class )
public @interface HttpCode {
String message() default "must be a valid http code";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}

View File

@@ -0,0 +1,39 @@
package com.r11.tools.model.constraints;
import com.r11.tools.model.MockedMessage;
import com.r11.tools.model.MockedMessageDto;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import org.springframework.http.HttpStatus;
/**
* It's validator class. It checks if status value of {@link MockedMessageDto} is within bonds of http status values map.
* @author Rafał Żukowicz
*/
public class HttpCodeValidation implements ConstraintValidator<HttpCode, Integer> {
private Set<Integer> allowedValues;
/**
* Initializes {@link #allowedValues} with possible http status values.
* @param targetEnum HttpCode context
*/
@Override
public void initialize(HttpCode targetEnum) {
allowedValues = Stream.of(HttpStatus.values())
.map(HttpStatus::value)
.collect(Collectors.toSet());
}
/**
* @param integer value of {@link MockedMessageDto#getHttpStatus()} or {@link MockedMessage#getHttpStatus()}
* @param context context for validation
* @return true if valid
*/
@Override
public boolean isValid(Integer integer, ConstraintValidatorContext context) {
return allowedValues.contains(integer);
}
}

View File

@@ -0,0 +1,20 @@
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);
}

View File

@@ -0,0 +1,99 @@
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;
}
}

View File

@@ -0,0 +1,23 @@
package com.r11.tools.repository;
import com.r11.tools.model.MockedMessage;
import java.util.List;
import java.util.UUID;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
/**
* Spring repository that allows to retrieve message list by key-uuid from redis database
* @author Rafał Żukowicz
*/
@Repository
@Transactional
public interface MockedResponseRepository extends CrudRepository<MockedMessage, String> {
/**
* Finds all messages by their uuid
* @param clientUUID the key-uuid of given set of messages
* @return list of {@link com.r11.tools.model.MockedMessage}
*/
List<MockedMessage> findAllByClientUUID(UUID clientUUID);
}

View File

@@ -0,0 +1,20 @@
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);
}

View File

@@ -0,0 +1,45 @@
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 java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* Spring Service for {@link com.r11.tools.controller.EventController}. Contains logic required for quering
* the database for {@link Event} objects
* @author Rafał Żukowicz
*/
@Slf4j
@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;
}
}

View File

@@ -0,0 +1,19 @@
package com.r11.tools.service;
import com.r11.tools.model.MockedMessageDto;
import java.util.List;
import java.util.UUID;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
/**
* Service interface for {@link com.r11.tools.controller.KlausController} and {@link com.r11.tools.controller.MockController}
* @author Rafał Żukowicz
*/
@Service
public interface KlausService {
ResponseEntity<String> deleteMockedResponse(UUID clientUUID, int mockedResponseId);
List<MockedMessageDto> getAllMockedResponses(UUID clientUUID);
MockedMessageDto getMockedResponse(UUID clientUUID, int mockedResponseId);
ResponseEntity<String> setMockedResponse(MockedMessageDto mockedMessageDto);
}

View File

@@ -0,0 +1,99 @@
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;
import com.r11.tools.repository.MockedResponseRepository;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
/**
* Service for {@link com.r11.tools.controller.MockController} and {@link com.r11.tools.controller.MockController}
* Allows for performing CRUD operations on {@link MockedMessageDto}
* @author Rafał Żukowicz
* @author Gabriel Modzelewski
*/
@Slf4j
@Service
@AllArgsConstructor
public class KlausServiceImpl implements KlausService {
private final MockedMessageMapper mockedMessageMapper;
private final MockedResponseRepository mockedResponseRepository;
private final ObjectMapper objectMapper;
/**
* Removes message of given id in given key-uuid set
* @param clientUUID the key-uuid of given set of messages
* @param mockedResponseId unique id of given message
* @return confirmation and status 200 OK
*/
@Override
public ResponseEntity<String> deleteMockedResponse(UUID clientUUID, int mockedResponseId) {
String key = clientUUID.toString() + "_" + mockedResponseId;
mockedResponseRepository.deleteById(key);
log.info("Message " + mockedResponseId + " has been removed.");
return new ResponseEntity<>("MockedResponse has been removed successfully",
new HttpHeaders(), HttpStatus.ACCEPTED);
}
/**
* Returns all messages of given key-uuid
* @param clientUUID the key-uuid of given set of messages
* @return List of {@link MockedMessageDto}
*/
@Override
public List<MockedMessageDto> getAllMockedResponses(UUID clientUUID) {
return mockedResponseRepository.findAllByClientUUID(clientUUID).stream()
.map(mockedMessageMapper::mockedMessageToMockedMessageDto)
.collect(Collectors.toList());
}
/**
* Returns {@link MockedMessageDto} of given id and key-uuid. If message doesn't then empty message is returned
* @param clientUUID the key-uuid of given set of messages
* @param mockedResponseId unique id of given message
* @return {@link MockedMessageDto} object
*/
@SneakyThrows
@Override
public MockedMessageDto getMockedResponse(UUID clientUUID, int mockedResponseId){
String key = clientUUID.toString() + "_" + mockedResponseId;
Optional<MockedMessage> optionalMockedMessage = mockedResponseRepository.findById(key);
MockedMessageDto mockedMessageDto = MockedMessageDto.builder()
.clientUUID(clientUUID)
.mockedResponseId(mockedResponseId)
.build();
if (optionalMockedMessage.isPresent()) {
mockedMessageDto = mockedMessageMapper.mockedMessageToMockedMessageDto(optionalMockedMessage.get());
log.info(mockedMessageDto.toString().replaceAll("\"", "\\\\\""));
return mockedMessageDto;
}
log.info(mockedMessageDto.toString().replaceAll("\"", "\\\\\""));
return mockedMessageDto;
}
/**
* Allows to modify mocked message. If message of given id and key-uuid doesn't exist a new entry is created
* @param mockedMessageDto message to be saved
* @return Confirmation and status 200 OK
*/
@SneakyThrows
@Override
public ResponseEntity<String> setMockedResponse(MockedMessageDto mockedMessageDto) {
mockedResponseRepository.save(mockedMessageMapper.mockedMessageDtoToMockedMessage(mockedMessageDto));
log.info(mockedMessageDto.toString().replaceAll("\"", "\\\\\""));
return new ResponseEntity<>("MockedResponse has been setup successfully!", new HttpHeaders(),
HttpStatus.ACCEPTED);
}
}

View File

@@ -0,0 +1,24 @@
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;
}
}

View File

@@ -0,0 +1,235 @@
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();
}
}

View File

@@ -0,0 +1,24 @@
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());
}
}
}