Skip to content

Commit

Permalink
set Locale to US (and Log)
Browse files Browse the repository at this point in the history
set Timezone to UTC (and Log)
first implementation of command-bus, api and database
  • Loading branch information
svencc committed Sep 2, 2023
1 parent 7ca12e5 commit 0da18b0
Show file tree
Hide file tree
Showing 17 changed files with 416 additions and 28 deletions.
18 changes: 17 additions & 1 deletion TODO.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,23 @@
# TODO LIST
*
* Command Framework
* add real JSON endpoints in addition to the necessary "consuming = MediaType.APPLICATION_FORM_URLENCODED_VALUE" Endpoints ...
* Table with commands
* MapName
* Command Type
* Timestamp
* Command Data / Payload
* API for fetching commands
* different flavours
* fetch all
* fetch last command of each type
* fetch last command of type
* existing command types
*
*
*
*
*
*
* Transactions have to time out via scheduler after one hour
*
* normalize db/map entities table
Expand Down
21 changes: 21 additions & 0 deletions diagrams/Sequence.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
'https://plantuml.com/de/sequence-diagram

@startuml
'header Command Poll Flow
title Command Poll Flow

participant CLIENT
participant SERVER
database DB

CLIENT -> SERVER: authenticate
SERVER --> CLIENT: send JWT Token


CLIENT -> SERVER: Poll for Commands
SERVER --> DB: Query for latest Commands
DB --> SERVER: Send Commands

CLIENT <-- SERVER: give Commands
CLIENT --> CLIENT: execute Commands
@enduml
22 changes: 22 additions & 0 deletions diagrams/StateMachine.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
@startuml
'https://plantuml.com/state-diagram
'https://github.com/pnavais/state-machine

'https://www.baeldung.com/spring-state-machine
' https://github.com/64ink/spring-statemachine-chart-exporter
' https://plantuml.com/de/api
' https://plantuml.com/de/download

'scale 500 width


[*] --> INIT_NewGame : start game
INIT_NewGame: generate basic commands (if not present)
INIT_NewGame --> RUN : initialized
RUN --> STOPPED : stop
RUN --> PAUSE : pause
PAUSE --> RUN : resume
STOPPED --> [*] : end

@enduml

12 changes: 11 additions & 1 deletion src/main/java/com/recom/Application.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
import org.springframework.context.annotation.Profile;
import org.springframework.web.filter.CommonsRequestLoggingFilter;

import java.util.Locale;
import java.util.TimeZone;

@EnableCaching
@SpringBootApplication(scanBasePackages = {"com.recom"})
@EnableConfigurationProperties({
Expand All @@ -20,11 +23,18 @@
public class Application {

public static void main(String[] args) {
// Set default locale to US
Locale.setDefault(Locale.US);
// Set default timezone to UTC
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));

// Start Spring Boot Application
final ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);

// Start Spring Context
context.start();
}

// Uncomment to log all requests to console
// SET in application.properties -> logging.level.org.springframework.web.filter.CommonsRequestLoggingFilter: DEBUG
@Bean
@Profile("local")
Expand Down
75 changes: 75 additions & 0 deletions src/main/java/com/recom/api/commandbus/CommandBusController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package com.recom.api.commandbus;

import com.recom.api.commons.HttpCommons;
import com.recom.dto.command.CommandDto;
import com.recom.persistence.command.CommandPersistenceLayer;
import com.recom.service.AssertionService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.CacheControl;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@Slf4j
@Validated
@RestController
@RequiredArgsConstructor
@Tag(name = "CommandBus")
@RequestMapping("/api/v1/command-bus")
public class CommandBusController {

@NonNull
private final AssertionService assertionService;
@NonNull
private final CommandPersistenceLayer commandPersistenceLayer;


@Operation(
summary = "Get a list of commands",
description = "Gets all map specific, latest commands of a type.",
security = @SecurityRequirement(name = HttpCommons.BEARER_AUTHENTICATION_REQUIREMENT)
)
@ApiResponses(value = {
@ApiResponse(responseCode = HttpCommons.OK_CODE, description = HttpCommons.OK),
@ApiResponse(responseCode = HttpCommons.UNAUTHORIZED_CODE, description = HttpCommons.UNAUTHORIZED, content = @Content())
})
@GetMapping(path = "", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<List<CommandDto>> getCommands(
@RequestParam(required = true)
@NonNull final String mapName
) {
log.debug("Requested GET /api/v1/map/command-bus");

// @TODO: re-enable after development
// assertionService.assertMapExists(mapName);

final List<CommandDto> allMapSpecificCommands = commandPersistenceLayer.findAllMapSpecificCommands(mapName);

if (allMapSpecificCommands.isEmpty()) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.cacheControl(CacheControl.noCache())
.build();
} else {
return ResponseEntity.status(HttpStatus.OK)
.cacheControl(CacheControl.noCache())
.body(allMapSpecificCommands);
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.recom.configuration;

import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;

import java.util.Locale;
import java.util.TimeZone;

@Slf4j
@Configuration
public class LocaleLoggerConfiguration implements AsyncConfigurer {

@PostConstruct
public void init() {
log.info("Locale initialized with '{}'", Locale.getDefault());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.recom.configuration;

import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;

import java.util.Locale;
import java.util.TimeZone;

@Slf4j
@Configuration
public class TimezoneLoggerConfiguration implements AsyncConfigurer {

@PostConstruct
public void init() {
log.info("Timezone initialized with '{}'", TimeZone.getDefault().getDisplayName());
}

}
23 changes: 0 additions & 23 deletions src/main/java/com/recom/dto/ServerErrorDto.java

This file was deleted.

45 changes: 45 additions & 0 deletions src/main/java/com/recom/dto/command/CommandDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.recom.dto.command;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.recom.model.command.CommandType;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.persistence.Column;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.Nationalized;

@Data
@Schema
@Builder
@NoArgsConstructor
@AllArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class CommandDto {

@Schema
@JsonProperty()
private Long id;

@Schema
@JsonProperty()
private String mapName;

@Schema
@JsonProperty()
private CommandType commandType;

@Schema(description = "Unix timestamp in milliseconds", example = "1691941419964")
@JsonProperty()
private Long timestampEpochMilliseconds;

@Schema
@JsonProperty()
private String payload;

}
81 changes: 81 additions & 0 deletions src/main/java/com/recom/entity/Command.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package com.recom.entity;

import com.recom.model.command.CommandType;
import jakarta.persistence.*;
import lombok.*;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.hibernate.annotations.Nationalized;
import org.springframework.data.domain.Persistable;

import java.io.Serializable;
import java.time.LocalDateTime;

@Getter
@Setter
@Entity
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(indexes = {
@Index(name = "IDX_mapName", columnList = "mapName", unique = false),
@Index(name = "IDX_mapName_commandType", columnList = "mapName, commandType", unique = false),
@Index(name = "IDX_mapName_commandType_timestamp", columnList = "mapName, commandType, timestamp", unique = true),
@Index(name = "IDX_mapName_timestamp", columnList = "mapName, timestamp", unique = false),
})
@Cacheable
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Command implements Persistable<Long>, Serializable {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(insertable = true, updatable = false, nullable = false)
private Long id;

@Nationalized
@Column(insertable = true, updatable = false, nullable = false, length = 255)
private String mapName;

@Enumerated(EnumType.STRING)
@Column(insertable = true, updatable = false, nullable = false, length = 255)
private CommandType commandType;

@Column(insertable = true, updatable = false, nullable = false, columnDefinition="DATETIME(6) DEFAULT NOW(6)")
private LocalDateTime timestamp;

@Lob
@Column(insertable = true, updatable = true, nullable = true, columnDefinition = "LONGTEXT")
private String payload;

@Override
public int hashCode() {
return Command.class.hashCode();
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else if (obj == null) {
return false;
} else if (getClass() != obj.getClass()) {
return false;
} else {
final Command other = (Command) obj;
if (getId() == null) {
return false;
} else return getId().equals(other.getId());
}
}

@Override
public Long getId() {
return id;
}

@Override
public boolean isNew() {
return getId() == null;
}

}
2 changes: 1 addition & 1 deletion src/main/java/com/recom/entity/Configuration.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
public class Configuration implements Persistable<Long>, Serializable {

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(insertable = true, updatable = false, nullable = false)
private Long id;

Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/recom/entity/DBCachedItem.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
public class DBCachedItem implements Persistable<Long>, Serializable {

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(insertable = true, updatable = false, nullable = false)
private Long id;

Expand Down
Loading

0 comments on commit 0da18b0

Please sign in to comment.