feat: 배포된 App 정보 조회

- 장비의 App 정보 조회
Closed: #SCDD-56
This commit is contained in:
hyunjujeong 2023-08-11 15:47:00 +09:00
parent 02bb5611f4
commit 59cb705c10
21 changed files with 256 additions and 99 deletions

View File

@ -3,7 +3,7 @@ package inc.sdt.blokworks.devicedeployer.application;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import inc.sdt.blokworks.devicedeployer.domain.AssetApp;
import inc.sdt.blokworks.devicedeployer.domain.DeployMessage;
import inc.sdt.blokworks.devicedeployer.domain.OutboundMessage;
import inc.sdt.blokworks.devicedeployer.domain.OperationType;
import inc.sdt.blokworks.devicedeployer.infrastructure.mqtt.InboundDeployMessagePayload;
import inc.sdt.blokworks.devicedeployer.infrastructure.mqtt.OutboundMessagePayload;
@ -12,6 +12,7 @@ import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;
@ -32,15 +33,14 @@ public class DefaultDeployerService implements DeployerService{
}
@Override
public void publish(DeployMessage deployMessage, String assetCode) {
public void publish(OutboundMessage deployMessage, String assetCode) {
log.info("[publish]");
try {
OutboundMessagePayload payload = new OutboundMessagePayload(
deployMessage.getUrl(),
deployMessage.getName(),
deployMessage.getPorts(),
deployMessage.getEnv(),
deployMessage.getCommand(),
deployMessage.getEnv(),
OperationType.DEPLOY,
deployMessage.getRequestId()
);
@ -59,10 +59,18 @@ public class DefaultDeployerService implements DeployerService{
public Mono<Void> apply(InboundDeployMessagePayload inboundDeployMessagePayload) {
log.info("[apply] inboundDeployMessagePayload = {}", inboundDeployMessagePayload);
// 배포된 앱 정보 저장
deployerRepositoryDelegate.save(fromMessage(inboundDeployMessagePayload));
// request Id 판별
AssetApp assetApp = deployerRepositoryDelegate.save(fromMessage(inboundDeployMessagePayload));
return null;
}
@Override
public Page<AssetApp> getAll(String assetCode, int page, int size) {
log.debug("[getAll] assetCode = {}, page = {}, size = {}", assetCode, page, size);
return deployerRepositoryDelegate.findAllByAssetCode(assetCode, page, size);
}
private AssetApp fromMessage(InboundDeployMessagePayload payload) {
return AssetApp.builder()
.assetCode(payload.assetCode())

View File

@ -1,8 +1,9 @@
package inc.sdt.blokworks.devicedeployer.application;
import inc.sdt.blokworks.devicedeployer.domain.AssetApp;
import inc.sdt.blokworks.devicedeployer.domain.DeployMessage;
import org.springframework.data.domain.Page;
public interface DeployerRepositoryDelegate {
AssetApp save(AssetApp assetApp);
Page<AssetApp> findAllByAssetCode(String assetCode, int page, int size);
}

View File

@ -1,11 +1,14 @@
package inc.sdt.blokworks.devicedeployer.application;
import inc.sdt.blokworks.devicedeployer.domain.DeployMessage;
import inc.sdt.blokworks.devicedeployer.domain.AssetApp;
import inc.sdt.blokworks.devicedeployer.domain.OutboundMessage;
import inc.sdt.blokworks.devicedeployer.infrastructure.mqtt.InboundDeployMessagePayload;
import org.springframework.data.domain.Page;
import reactor.core.publisher.Mono;
import java.util.function.Function;
public interface DeployerService extends Function<InboundDeployMessagePayload, Mono<Void>> {
void publish(DeployMessage assetApp, String assetCode);
void publish(OutboundMessage assetApp, String assetCode);
Page<AssetApp> getAll(String assetCode, int page, int size);
}

View File

@ -1,7 +1,5 @@
package inc.sdt.blokworks.devicedeployer.domain;
import java.sql.Timestamp;
public class AssetApp {
private String assetCode;
private String name;

View File

@ -3,16 +3,15 @@ package inc.sdt.blokworks.devicedeployer.domain;
import java.util.HashMap;
import java.util.Set;
public class DeployMessage {
public class OutboundMessage {
private String url;
private String name;
private Set<Port> ports;
private HashMap<String, String> env;
private String command;
private OperationType operationType;
private String requestId;
protected DeployMessage() {}
protected OutboundMessage() {}
public String getUrl() {
return url;
@ -22,10 +21,6 @@ public class DeployMessage {
return name;
}
public Set<Port> getPorts() {
return ports;
}
public HashMap<String, String> getEnv() {
return env;
}
@ -51,7 +46,6 @@ public class DeployMessage {
return "AssetApp{" +
"url='" + url + '\'' +
", name='" + name + '\'' +
", ports=" + ports +
", env=" + env +
", command='" + command + '\'' +
", operationType=" + operationType +
@ -66,7 +60,6 @@ public class DeployMessage {
public static final class Builder {
private String url;
private String name;
private Set<Port> ports;
private HashMap<String, String> env;
private String command;
private OperationType operationType;
@ -82,11 +75,6 @@ public class DeployMessage {
return this;
}
public Builder ports(Set<Port> ports) {
this.ports = ports;
return this;
}
public Builder env(HashMap<String, String> env) {
this.env = env;
return this;
@ -107,11 +95,10 @@ public class DeployMessage {
return this;
}
public DeployMessage build() {
DeployMessage deployMessage = new DeployMessage();
public OutboundMessage build() {
OutboundMessage deployMessage = new OutboundMessage();
deployMessage.url = this.url;
deployMessage.name = this.name;
deployMessage.ports = this.ports;
deployMessage.env = this.env;
deployMessage.command = this.command;
deployMessage.operationType = this.operationType;

View File

@ -8,6 +8,7 @@ public record InboundDeployMessagePayload(
String name,
Long size,
Long releasedAt,
Long modifiedAt
Long modifiedAt,
String requestId
) {
}

View File

@ -11,9 +11,8 @@ import java.util.Set;
public record OutboundMessagePayload(
String url,
String name,
Set<Port> ports,
HashMap<String, String> env,
String command,
HashMap<String, String> env,
OperationType operationType,
String requestId
) {

View File

@ -23,8 +23,7 @@ class AssetAppEntity {
protected AssetAppEntity() {}
public AssetAppEntity(String id, String assetCode, String name, long size, Long releasedAt, Long modifiedAt) {
this.id = id;
public AssetAppEntity(String assetCode, String name, long size, Long releasedAt, Long modifiedAt) {
this.assetCode = assetCode;
this.name = name;
this.size = size;

View File

@ -1,7 +1,9 @@
package inc.sdt.blokworks.devicedeployer.infrastructure.relational;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
public interface AssetAppJpaRepository extends JpaRepository<AssetAppEntity, String> {
Page<AssetAppEntity> findAllByAssetCode(String assetCode, Pageable pageable);
}

View File

@ -2,9 +2,12 @@ package inc.sdt.blokworks.devicedeployer.infrastructure.relational;
import inc.sdt.blokworks.devicedeployer.application.DeployerRepositoryDelegate;
import inc.sdt.blokworks.devicedeployer.domain.AssetApp;
import inc.sdt.blokworks.devicedeployer.domain.DeployMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Component;
@Component
@ -17,10 +20,40 @@ public class AssetAppRelationalRepository implements DeployerRepositoryDelegate
this.assetAppJpaRepository = assetAppJpaRepository;
}
// 앱 정보 저장
@Override
public AssetApp save(AssetApp deployMessage) {
public AssetApp save(AssetApp assetApp) {
AssetAppEntity entity = this.toEntity(assetApp);
assetAppJpaRepository.save(entity);
return assetApp;
}
return null;
@Override
public Page<AssetApp> findAllByAssetCode(String assetCode, int page, int size) {
log.debug("[findAllByAssetCode] assetCode = {}", assetCode);
Pageable pageable = page < 0 ? Pageable.unpaged() : PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "releasedAt"));
return assetAppJpaRepository.findAllByAssetCode(assetCode, pageable)
.map(this::fromEntity);
}
private AssetAppEntity toEntity(AssetApp assetApp) {
return new AssetAppEntity(
assetApp.getAssetCode(),
assetApp.getName(),
assetApp.getSize(),
assetApp.getReleaseAt(),
assetApp.getModifiedAt()
);
}
private AssetApp fromEntity(AssetAppEntity entity) {
return AssetApp.builder()
.assetCode(entity.getAssetCode())
.name(entity.getName())
.size(entity.getSize())
.releasedAt(entity.getReleasedAt())
.modifiedAt(entity.getModifiedAt())
.build();
}
}

View File

@ -1,18 +1,10 @@
package inc.sdt.blokworks.devicedeployer.presentation;
import org.wildfly.common.annotation.NotNull;
import java.util.HashMap;
import java.util.Set;
record AssetAppResource(
@NotNull
String url,
@NotNull
String assetCode,
String name,
Set<PortResource> ports,
HashMap<String, String> env,
String command
Long size,
Long releaseAt,
Long modifiedAt
) {
}

View File

@ -1,41 +1,28 @@
package inc.sdt.blokworks.devicedeployer.presentation;
import inc.sdt.blokworks.devicedeployer.domain.DeployMessage;
import inc.sdt.blokworks.devicedeployer.domain.AssetApp;
import org.springframework.stereotype.Component;
import java.util.HashSet;
import java.util.stream.Collectors;
@Component
public class AssetAppResourceConverter {
private final PortResourceConverter portResourceConverter;
public AssetAppResourceConverter(PortResourceConverter portResourceConverter) {
this.portResourceConverter = portResourceConverter;
public AssetApp fromResource(AssetAppResource resource) {
return AssetApp.builder()
.assetCode(resource.assetCode())
.name(resource.name())
.size(resource.size())
.releasedAt(resource.releaseAt())
.modifiedAt(resource.modifiedAt())
.build();
}
public AssetAppResource toResource(DeployMessage deployMessage) {
public AssetAppResource toResource(AssetApp assetApp) {
return new AssetAppResource(
deployMessage.getUrl(),
deployMessage.getName(),
deployMessage.getPorts() != null
? deployMessage.getPorts().stream().map(portResourceConverter::toResource).collect(Collectors.toSet())
: null,
deployMessage.getEnv(),
deployMessage.getCommand()
assetApp.getAssetCode(),
assetApp.getName(),
assetApp.getSize(),
assetApp.getReleaseAt(),
assetApp.getModifiedAt()
);
}
public DeployMessage fromResource(AssetAppResource resource) {
return DeployMessage.builder()
.url(resource.url())
.name(resource.name())
.ports(resource.ports() != null
? resource.ports().stream().map(portResourceConverter::fromResource).collect(Collectors.toSet())
: new HashSet<>())
.env(resource.env())
.command(resource.command())
.build();
}
}

View File

@ -1,24 +1,33 @@
package inc.sdt.blokworks.devicedeployer.presentation;
import inc.sdt.blokworks.devicedeployer.application.DeployerService;
import inc.sdt.blokworks.devicedeployer.domain.DeployMessage;
import inc.sdt.blokworks.devicedeployer.domain.AssetApp;
import inc.sdt.blokworks.devicedeployer.domain.OperationType;
import inc.sdt.blokworks.devicedeployer.domain.OutboundMessage;
import jakarta.servlet.http.HttpSession;
import jakarta.validation.Valid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import java.util.UUID;
@RestController
public class DeployerController {
private final Logger log;
private final DeployerService deployerService;
private final AssetAppResourceConverter appResourceConverter;
private final OutboundMessageResourceConverter outboundMessageResourceConverter;
private final AssetAppResourceConverter assetAppResourceConverter;
public DeployerController(DeployerService deployerService,
AssetAppResourceConverter appResourceConverter) {
OutboundMessageResourceConverter outboundMessageResourceConverter,
AssetAppResourceConverter assetAppResourceConverter) {
this.log = LoggerFactory.getLogger(this.getClass());
this.deployerService = deployerService;
this.appResourceConverter = appResourceConverter;
this.outboundMessageResourceConverter = outboundMessageResourceConverter;
this.assetAppResourceConverter = assetAppResourceConverter;
}
/**
@ -29,20 +38,24 @@ public class DeployerController {
@ResponseStatus(HttpStatus.CREATED)
@PostMapping("/assets/{assetCode}/apps")
public void deploy(@PathVariable String assetCode,
@Valid @RequestBody AssetAppResource assetAppResource) {
@Valid @RequestBody OutboundMessageResource assetAppResource) {
log.info("[deploy] assetCode = {}, assetAppResource = {}", assetCode, assetAppResource);
DeployMessage deployMessage = appResourceConverter.fromResource(assetAppResource);
deployMessage.setRequestId("requestId");
deployerService.publish(appResourceConverter.fromResource(assetAppResource), assetCode);
OutboundMessage outboundMessage = outboundMessageResourceConverter.fromResource(assetAppResource);
outboundMessage.setRequestId("requestId");
deployerService.publish(outboundMessageResourceConverter.fromResource(assetAppResource), assetCode);
}
/**
*
* ( )
* @param assetCode
*/
@ResponseStatus(HttpStatus.OK)
@GetMapping("/assets/{assetCode}/apps")
public void get(@PathVariable String assetCode) {
log.info("[get] assetCode = {}", assetCode);
public PageableResponse<AssetAppResource> get(@PathVariable String assetCode,
@RequestParam(required = false, defaultValue = "0") int page,
@RequestParam(required = false, defaultValue = "20") int size) {
log.info("[get] assetCode = {}, page = {}, size = {}", assetCode, page, size);
Page<AssetApp> assetApps = deployerService.getAll(assetCode, page, size);
return PageableResponse.from(assetApps, assetAppResourceConverter::toResource);
}
}

View File

@ -1,5 +1,6 @@
package inc.sdt.blokworks.devicedeployer.presentation;
import com.fasterxml.jackson.databind.ObjectMapper;
import inc.sdt.blokworks.devicedeployer.application.DeployerService;
import inc.sdt.blokworks.devicedeployer.application.ProcessService;
import inc.sdt.blokworks.devicedeployer.infrastructure.mqtt.InboundDeployMessagePayload;
@ -8,6 +9,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.integration.annotation.MessageEndpoint;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.mqtt.support.MqttHeaders;
import org.springframework.messaging.Message;
@MessageEndpoint
@ -15,16 +17,19 @@ public class MqttMessageHandler {
private final Logger log;
private final DeployerService deployerService;
private final ProcessService processService;
private final ObjectMapper objectMapper;
private final MqttMessageConverter<InboundDeployMessagePayload> deployMessagePayloadConverter;
private final MqttMessageConverter<InboundProcessMessagePayload> processMessagePayloadConverter;
public MqttMessageHandler(DeployerService deployerService,
ProcessService processService,
ObjectMapper objectMapper,
MqttMessageConverter<InboundDeployMessagePayload> deployMessagePayloadConverter,
MqttMessageConverter<InboundProcessMessagePayload> processMessagePayloadConverter) {
this.log = LoggerFactory.getLogger(this.getClass());
this.deployerService = deployerService;
this.processService = processService;
this.objectMapper = objectMapper;
this.deployMessagePayloadConverter = deployMessagePayloadConverter;
this.processMessagePayloadConverter = processMessagePayloadConverter;
}
@ -34,7 +39,20 @@ public class MqttMessageHandler {
log.debug("[handleMessage] message={}", message);
if(!message.getPayload().contains("pid")) {
String topic = String.valueOf(message.getHeaders().get(MqttHeaders.RECEIVED_TOPIC));
String id = topic.split("/")[1];
log.info("[handleMessage] topic = {}, id = {}", topic, id);
deployMessagePayloadConverter.convertFromByte(message.getPayload(), InboundDeployMessagePayload.class)
.map(p -> new InboundDeployMessagePayload(
p.status(),
p.assetCode(),
p.name(),
p.size(),
p.releasedAt(),
p.modifiedAt(),
id))
.flatMap(deployerService)
.subscribe();
}else {

View File

@ -0,0 +1,16 @@
package inc.sdt.blokworks.devicedeployer.presentation;
import org.wildfly.common.annotation.NotNull;
import java.util.HashMap;
record OutboundMessageResource(
@NotNull
String url,
@NotNull
String name,
String command,
HashMap<String, String> env
) {
}

View File

@ -0,0 +1,27 @@
package inc.sdt.blokworks.devicedeployer.presentation;
import inc.sdt.blokworks.devicedeployer.domain.OutboundMessage;
import org.springframework.stereotype.Component;
@Component
public class OutboundMessageResourceConverter {
public OutboundMessageResource toResource(OutboundMessage outboundMessage) {
return new OutboundMessageResource(
outboundMessage.getUrl(),
outboundMessage.getName(),
outboundMessage.getCommand(),
outboundMessage.getEnv()
);
}
public OutboundMessage fromResource(OutboundMessageResource resource) {
return OutboundMessage.builder()
.url(resource.url())
.name(resource.name())
.command(resource.command())
.env(resource.env())
.build();
}
}

View File

@ -0,0 +1,8 @@
package inc.sdt.blokworks.devicedeployer.presentation;
interface PageableResource {
long getTotalElements();
int getTotalPages();
int getSize();
int getPage();
}

View File

@ -0,0 +1,45 @@
package inc.sdt.blokworks.devicedeployer.presentation;
import org.springframework.data.domain.Page;
class PageableResourceImpl implements PageableResource {
private final long totalElements;
private final int totalPages;
private final int size;
private final int page;
PageableResourceImpl(long totalElements, int totalPages, int size, int page) {
this.totalElements = totalElements;
this.totalPages = totalPages;
this.size = size;
this.page = page;
}
static <T> PageableResourceImpl from(Page<T> page) {
return new PageableResourceImpl(
page.getTotalElements(),
page.getTotalPages(),
page.getSize(),
page.getPageable().getPageNumber());
}
@Override
public long getTotalElements() {
return 0;
}
@Override
public int getTotalPages() {
return 0;
}
@Override
public int getSize() {
return 0;
}
@Override
public int getPage() {
return 0;
}
}

View File

@ -0,0 +1,28 @@
package inc.sdt.blokworks.devicedeployer.presentation;
import org.springframework.data.domain.Page;
import java.util.List;
import java.util.function.Function;
class PageableResponse<T> {
private final List<T> content;
private final PageableResource pageable;
PageableResponse(List<T> content, PageableResource pageable) {
this.content = content;
this.pageable = pageable;
}
static <T, U> PageableResponse<U> from(Page<T> page, Function<T, U> converter) {
return new PageableResponse<>(page.map(converter).getContent(), PageableResourceImpl.from(page));
}
public List<T> getContent() {
return content;
}
public PageableResource getPageable() {
return pageable;
}
}

View File

@ -16,9 +16,5 @@ inbound:
username: sdt
password: 251327
topics:
- /assets/+/apps/process
- /assets/+/apps/deploy
outbound:
mqtt:
topic:
- /assets/+/command-req/+
- /assets/+/command-req/+
- /assets/+/apps/process

View File

@ -12,9 +12,5 @@ inbound:
username: sdt
password: 251327
topics:
- /assets/+/apps/process
- /assets/+/apps/deploy
outbound:
mqtt:
topic:
- /assets/+/command-req/+
- /assets/+/command-req/+
- /assets/+/apps/process