Tube On/Off 제어 기능 개발

This commit is contained in:
장선애 2023-09-08 10:17:39 +09:00
parent 0998142c2c
commit 8cc8097f33
25 changed files with 942 additions and 1 deletions

View File

@ -5,13 +5,24 @@ plugins {
} }
group = 'inc.sdt.controlcentermanagement' group = 'inc.sdt.controlcentermanagement'
version = '0.0.1-SNAPSHOT' version = '0.0.1'
java { java {
sourceCompatibility = '17' sourceCompatibility = '17'
} }
def codeArtifactToken = "aws codeartifact get-authorization-token --domain sdt --domain-owner 003960268191 --region ap-northeast-1 --query authorizationToken --output text".execute().text
repositories { repositories {
maven {
url 'https://sdt-003960268191.d.codeartifact.ap-northeast-1.amazonaws.com/maven/sdt-development/'
credentials {
username "aws"
password codeArtifactToken
}
// url 'http://192.168.1.232:8081/repository/maven-releases/'
// allowInsecureProtocol true
}
mavenCentral() mavenCentral()
} }
@ -21,6 +32,7 @@ dependencies {
} }
implementation("org.springframework.boot:spring-boot-starter-undertow") implementation("org.springframework.boot:spring-boot-starter-undertow")
implementation("org.springframework.boot:spring-boot-starter-data-mongodb") implementation("org.springframework.boot:spring-boot-starter-data-mongodb")
implementation("org.springframework.boot:spring-boot-starter-amqp")
testImplementation ("org.springframework.boot:spring-boot-starter-test") testImplementation ("org.springframework.boot:spring-boot-starter-test")
} }

View File

@ -2,6 +2,8 @@ package inc.sdt.controlcentermanagement;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication @SpringBootApplication
public class ControlCenterManagementApplication { public class ControlCenterManagementApplication {
@ -10,4 +12,8 @@ public class ControlCenterManagementApplication {
SpringApplication.run(ControlCenterManagementApplication.class, args); SpringApplication.run(ControlCenterManagementApplication.class, args);
} }
@Bean
RestTemplate restTemplate() {
return new RestTemplate();
}
} }

View File

@ -0,0 +1,124 @@
package inc.sdt.controlcentermanagement.application;
import com.fasterxml.jackson.core.type.TypeReference;
import inc.sdt.controlcentermanagement.domain.CommandType;
import inc.sdt.controlcentermanagement.domain.DeployRequest;
import inc.sdt.controlcentermanagement.domain.Slot;
import inc.sdt.controlcentermanagement.domain.Tube;
import inc.sdt.controlcentermanagement.infrastructure.resttemplate.RestTemplateRequestHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.util.UriComponentsBuilder;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* @author sunae.jang (sa.jang@sdt.inc)
*/
@Service
class DefaultTubeService implements TubeService {
private final SlotRepositoryDelegate slotRepositoryDelegate;
private final RestTemplateRequestHandler restTemplateHandler;
private final String deployerEndpoint;
private final Logger log;
public DefaultTubeService(SlotRepositoryDelegate slotRepositoryDelegate, RestTemplateRequestHandler restTemplateHandler, @Value("${deployer.endpoint}") String deployerEndpoint) {
this.slotRepositoryDelegate = slotRepositoryDelegate;
this.restTemplateHandler = restTemplateHandler;
this.deployerEndpoint = deployerEndpoint;
this.log = LoggerFactory.getLogger(DefaultTubeService.class);
}
@Override
public List<Slot> get(String chamberNumber) {
log.info("[get] chamberNumber: {}", chamberNumber);
return slotRepositoryDelegate.get(chamberNumber);
}
@Override
public void controlByTubeCode(String authorization, Slot request) {
log.info("[controlByTubeCode] request: {}", request);
Map<String, String> tubeMap = new LinkedHashMap<>();
for (Tube tube : request.getTube()) {
Map<String, Integer> tubeOffsetMap = this.tubeOffset(request);
String offsetKey = request.getSlotNumber().substring(request.getSlotNumber().length() - 1);
int tubeOffset = tubeOffsetMap.getOrDefault(offsetKey, 1);
int tubeKey = Integer.parseInt(tube.getCode()) + tubeOffset;
tubeMap.put(String.valueOf(tubeKey), String.valueOf(request.getCommand().ordinal()));
}
DeployRequest deployRequest = DeployRequest.builder()
.assetCode(request.getAssetCode())
.deviceType("nodeq")
.appName(request.getSlotNumber())
.commandType(CommandType.JSON)
.parameters(tubeMap)
.build();
this.invokeDeployer(request.getAssetCode(), authorization, deployRequest);
}
@Override
public void controlAll(String authorization, Slot request) {
log.info("[controlAll] request: {}", request);
List<Slot> slots = this.get(request.getChamberNumber());
Map<String, Map<String, Map<String, String>>> resultMap = new LinkedHashMap<>();
for (Slot slot : slots) {
String assetCode = slot.getAssetCode();
String slotNumber = slot.getSlotNumber();
List<Tube> tubes = slot.getTube();
Map<String, Map<String, String>> assetMap = resultMap.computeIfAbsent(assetCode, k -> new HashMap<>());
Map<String, String> slotMap = assetMap.computeIfAbsent(slotNumber, k -> new HashMap<>());
for (Tube tube : tubes) {
Map<String, Integer> tubeOffsetMap = this.tubeOffset(request);
String offsetKey = slotNumber.substring(slotNumber.length() - 1);
int tubeOffset = tubeOffsetMap.getOrDefault(offsetKey, 1);
int offsetResult = Integer.parseInt(tube.getCode()) + tubeOffset;
slotMap.put(String.valueOf(offsetResult), String.valueOf(request.getCommand().ordinal()));
}
}
resultMap.forEach((assetCode, slot) -> slot.forEach((slotNumber, tube) -> {
DeployRequest deployRequest = DeployRequest.builder()
.assetCode(assetCode)
.deviceType("nodeq")
.appName(slotNumber)
.commandType(CommandType.JSON)
.parameters(tube)
.build();
this.invokeDeployer(assetCode, authorization, deployRequest);
}));
}
private Map<String, Integer> tubeOffset(Slot request) {
log.info("[tubeOffset] request: {}", request);
int offset = 0;
Map<String, Integer> tubeOffsetMap = new HashMap<>();
for (int i = 1; i <= 8; i++) {
tubeOffsetMap.put(String.valueOf(i), offset);
offset += 16;
if (i == 4) offset = 0;
}
return tubeOffsetMap;
}
private void invokeDeployer(String assetCode, String authorization, DeployRequest deployRequest) {
String url = UriComponentsBuilder.fromUriString(deployerEndpoint)
.path(String.format("/assets/%s/apps", assetCode))
.build()
.toUriString();
restTemplateHandler.httpPostRequestWithAuth(url, authorization, deployRequest, new TypeReference<>() {
});
}
}

View File

@ -0,0 +1,12 @@
package inc.sdt.controlcentermanagement.application;
import inc.sdt.controlcentermanagement.domain.Slot;
import java.util.List;
/**
* @author sunae.jang (sa.jang@sdt.inc)
*/
public interface SlotRepositoryDelegate {
List<Slot> get(String chamberNumber);
}

View File

@ -0,0 +1,14 @@
package inc.sdt.controlcentermanagement.application;
import inc.sdt.controlcentermanagement.domain.Slot;
import java.util.List;
/**
* @author sunae.jang (sa.jang@sdt.inc)
*/
public interface TubeService {
List<Slot> get(String chamberNumber);
void controlByTubeCode(String authorization, Slot request);
void controlAll(String authorization, Slot request);
}

View File

@ -0,0 +1,9 @@
package inc.sdt.controlcentermanagement.domain;
/**
* @author sunae.jang (sa.jang@sdt.inc)
*/
public enum Command {
OFF,
ON;
}

View File

@ -0,0 +1,14 @@
package inc.sdt.controlcentermanagement.domain;
/**
* @author sunae.jang (sa.jang@sdt.inc)
*/
public enum CommandType {
JSON("json");
private String type;
CommandType(String type) {
this.type = type;
}
}

View File

@ -0,0 +1,98 @@
package inc.sdt.controlcentermanagement.domain;
import java.util.Map;
/**
* @author sunae.jang (sa.jang@sdt.inc)
*/
public class DeployRequest {
private String assetCode;
private String deviceType;
private String appName;
private String commandType;
// private String fileName; // TODO: deployer에 추가되면 추가
private Map<String, String> parameters;
public DeployRequest(String assetCode, String deviceType, String appName, String commandType, Map<String, String> parameters) {
this.assetCode = assetCode;
this.deviceType = deviceType;
this.appName = appName;
this.commandType = commandType;
this.parameters = parameters;
}
public static Builder builder() {
return new Builder();
}
public String getAssetCode() {
return assetCode;
}
public String getDeviceType() {
return deviceType;
}
public String getAppName() {
return appName;
}
public String getCommandType() {
return commandType;
}
public Map<String, String> getParameters() {
return parameters;
}
@Override
public String toString() {
return "DeployRequest{" +
"assetCode='" + assetCode + '\'' +
", deviceType='" + deviceType + '\'' +
", appName='" + appName + '\'' +
", commandType=" + commandType +
", parameters=" + parameters +
'}';
}
public static final class Builder {
private String assetCode;
private String deviceType;
private String appName;
private String commandType;
private Map<String, String> parameters;
private Builder() {
}
public Builder assetCode(String assetCode) {
this.assetCode = assetCode;
return this;
}
public Builder deviceType(String deviceType) {
this.deviceType = deviceType;
return this;
}
public Builder appName(String appName) {
this.appName = appName;
return this;
}
public Builder commandType(CommandType commandType) {
this.commandType = commandType.toString().toLowerCase();
return this;
}
public Builder parameters(Map<String, String> parameters) {
this.parameters = parameters;
return this;
}
public DeployRequest build() {
return new DeployRequest(assetCode, deviceType, appName, commandType, parameters);
}
}
}

View File

@ -0,0 +1,117 @@
package inc.sdt.controlcentermanagement.domain;
import java.util.List;
/**
* @author sunae.jang (sa.jang@sdt.inc)
*/
public class Slot {
private String id;
private String slotNumber;
private String assetCode;
private List<Tube> tube;
private String chamberNumber;
private Command command;
protected Slot() {
}
public Slot(String id,String slotNumber, String assetCode, List<Tube> tube, String chamberNumber, Command command) {
this.id = id;
this.slotNumber = slotNumber;
this.assetCode = assetCode;
this.tube = tube;
this.chamberNumber = chamberNumber;
this.command = command;
}
public static Builder builder() {
return new Builder();
}
public String getId() {
return id;
}
public String getSlotNumber() {
return slotNumber;
}
public String getAssetCode() {
return assetCode;
}
public List<Tube> getTube() {
return tube;
}
public String getChamberNumber() {
return chamberNumber;
}
public void setChamberNumber(String chamberNumber) {
this.chamberNumber = chamberNumber;
}
public Command getCommand() {
return command;
}
@Override
public String toString() {
return "Slot{" +
"id='" + id + '\'' +
", slotNumber='" + slotNumber + '\'' +
", assetCode='" + assetCode + '\'' +
", tube=" + tube +
", chamberNumber='" + chamberNumber + '\'' +
", command=" + command +
'}';
}
public static final class Builder {
private String id;
private String slotNumber;
private String assetCode;
private List<Tube> tube;
private String chamberNumber;
private Command command;
private Builder() {
}
public Builder id(String id) {
this.id = id;
return this;
}
public Builder slotNumber(String slotNumber) {
this.slotNumber = slotNumber;
return this;
}
public Builder assetCode(String assetCode) {
this.assetCode = assetCode;
return this;
}
public Builder tube(List<Tube> tube) {
this.tube = tube;
return this;
}
public Builder chamberNumber(String chamberNumber) {
this.chamberNumber = chamberNumber;
return this;
}
public Builder Command(Command command) {
this.command = command;
return this;
}
public Slot build() {
return new Slot(id, slotNumber, assetCode, tube, chamberNumber, command);
}
}
}

View File

@ -0,0 +1,33 @@
package inc.sdt.controlcentermanagement.domain;
/**
* @author sunae.jang (sa.jang@sdt.inc)
*/
public class Tube {
private String code;
private String offset;
protected Tube() {
}
public Tube(String code, String offset) {
this.code = code;
this.offset = offset;
}
public String getCode() {
return code;
}
public String getOffset() {
return offset;
}
@Override
public String toString() {
return "Tube{" +
"number='" + code + '\'' +
", offset=" + offset +
'}';
}
}

View File

@ -0,0 +1,73 @@
package inc.sdt.controlcentermanagement.infrastructure.amqp;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "iam.amqp")
class IamAmqpConnectionProperties {
private String host;
private Integer port;
private String username;
private String password;
private String exchange;
private String routingKey;
public String getHost() {
return host;
}
void setHost(String host) {
this.host = host;
}
public Integer getPort() {
return port;
}
void setPort(Integer port) {
this.port = port;
}
public String getUsername() {
return username;
}
void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
void setPassword(String password) {
this.password = password;
}
public String getExchange() {
return exchange;
}
void setExchange(String exchange) {
this.exchange = exchange;
}
public String getRoutingKey() {
return routingKey;
}
void setRoutingKey(String routingKey) {
this.routingKey = routingKey;
}
@Override
public String toString() {
return "IamAmqpConnectionProperties{" +
"host='" + host + '\'' +
", port=" + port +
", username='" + username + '\'' +
", password='" + password + '\'' +
", exchange='" + exchange + '\'' +
", routingKey='" + routingKey + '\'' +
'}';
}
}

View File

@ -0,0 +1,47 @@
package inc.sdt.controlcentermanagement.infrastructure.amqp;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.ApplicationContext;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import java.util.Map;
import java.util.Objects;
@ConditionalOnProperty(prefix = "iam", name = "enabled", havingValue = "true")
@Component
class RegisterResourceMappingDelegate {
private final String applicationName;
private final RegisterResourceProducer registerResourceProducer;
private final Logger log;
RegisterResourceMappingDelegate(@Value("${spring.application.name}") String applicationName,
RegisterResourceProducer registerResourceProducer) {
this.log = LoggerFactory.getLogger(RegisterResourceMappingDelegate.class);
log.info("[Constructor] applicationName={}", applicationName);
this.registerResourceProducer = registerResourceProducer;
this.applicationName = applicationName;
}
@EventListener
public void handleContextRefreshedEvent(ContextRefreshedEvent event) {
log.info("[handleContextRefreshedEvent] event = {}", event);
ApplicationContext applicationContext = event.getApplicationContext();
RequestMappingHandlerMapping requestMappingHandlerMapping = applicationContext.getBean("requestMappingHandlerMapping", RequestMappingHandlerMapping.class);
Map<RequestMappingInfo, HandlerMethod> map = requestMappingHandlerMapping.getHandlerMethods();
map.values().stream()
.filter(value -> Objects.nonNull(value.getMethod().getDeclaredAnnotation(ResourceMapping.class)))
.map(value -> value.getMethod().getDeclaredAnnotation(ResourceMapping.class))
.map(annotation -> new ResourceMessagePayload(annotation.name(), annotation.method(), annotation.uri(), applicationName, annotation.description()))
.forEach(registerResourceProducer);
}
}

View File

@ -0,0 +1,56 @@
package inc.sdt.controlcentermanagement.infrastructure.amqp;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.function.Consumer;
@ConditionalOnProperty(prefix = "iam", name = "enabled", havingValue = "true")
@EnableConfigurationProperties({IamAmqpConnectionProperties.class})
@Component
class RegisterResourceProducer implements Consumer<ResourceMessagePayload> {
private final RabbitTemplate rabbitTemplate;
private final MessageConverter messageConverter;
private final MessageProperties messageProperties;
private final String exchange;
private final String routingKey;
private final Logger log;
RegisterResourceProducer(IamAmqpConnectionProperties connectionProperties) {
this.log = LoggerFactory.getLogger(RegisterResourceProducer.class);
log.info("[Constructor] connectionProperties={}", connectionProperties);
CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
connectionFactory.setHost(connectionProperties.getHost());
connectionFactory.setPort(connectionProperties.getPort());
connectionFactory.setUsername(connectionProperties.getUsername());
connectionFactory.setPassword(connectionProperties.getPassword());
this.messageConverter = new Jackson2JsonMessageConverter();
this.rabbitTemplate = new RabbitTemplate(connectionFactory);
this.rabbitTemplate.setMessageConverter(this.messageConverter);
this.exchange = connectionProperties.getExchange();
this.routingKey = connectionProperties.getRoutingKey();
this.messageProperties = new MessageProperties();
this.messageProperties.setContentType(MessageProperties.CONTENT_TYPE_JSON);
this.messageProperties.setHeader("Command", "CREATE");
}
@Override
public void accept(ResourceMessagePayload payload) {
log.info("[accept] payload={}", payload);
Message message = messageConverter.toMessage(payload, messageProperties);
rabbitTemplate.send(exchange, routingKey, message);
}
}

View File

@ -0,0 +1,15 @@
package inc.sdt.controlcentermanagement.infrastructure.amqp;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ResourceMapping {
String name();
String method();
String uri();
String description();
}

View File

@ -0,0 +1,4 @@
package inc.sdt.controlcentermanagement.infrastructure.amqp;
public record ResourceMessagePayload(String name, String method, String uri, String applicationName, String description) {
}

View File

@ -0,0 +1,58 @@
package inc.sdt.controlcentermanagement.infrastructure.nosql;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import java.util.List;
/**
* @author sunae.jang (sa.jang@sdt.inc)
*/
@Document("slot")
public class SlotDocument {
@Id
private String id;
private String slotNumber;
private String assetCode;
private List<TubeDocument> tube;
private String chamberNumber;
public SlotDocument(String id, String slotNumber, String assetCode, List<TubeDocument> tube, String chamberNumber) {
this.id = id;
this.slotNumber = slotNumber;
this.assetCode = assetCode;
this.tube = tube;
this.chamberNumber = chamberNumber;
}
public String getId() {
return id;
}
public String getSlotNumber() {
return slotNumber;
}
public String getAssetCode() {
return assetCode;
}
public List<TubeDocument> getTube() {
return tube;
}
public String getChamberNumber() {
return chamberNumber;
}
@Override
public String toString() {
return "SlotDocument{" +
"id='" + id + '\'' +
", slotNumber='" + slotNumber + '\'' +
", assetCode='" + assetCode + '\'' +
", tube=" + tube +
", chamberNumber='" + chamberNumber + '\'' +
'}';
}
}

View File

@ -0,0 +1,47 @@
package inc.sdt.controlcentermanagement.infrastructure.nosql;
import inc.sdt.controlcentermanagement.application.SlotRepositoryDelegate;
import inc.sdt.controlcentermanagement.domain.Slot;
import inc.sdt.controlcentermanagement.domain.Tube;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* @author sunae.jang (sa.jang@sdt.inc)
*/
@Repository
public class SlotNoSQLRepository implements SlotRepositoryDelegate {
private final SlotRepository slotRepository;
private final Logger log;
public SlotNoSQLRepository(SlotRepository slotRepository) {
this.slotRepository = slotRepository;
this.log = LoggerFactory.getLogger(SlotNoSQLRepository.class);
}
@Override
public List<Slot> get(String chamberNumber) {
log.debug("[get] chamberNumber: {}", chamberNumber);
return slotRepository.findAllByChamberNumber(chamberNumber)
.stream()
.map(this::to)
.toList();
}
private Slot to(SlotDocument slotDocument) {
return Slot.builder()
.id(slotDocument.getId())
.slotNumber(slotDocument.getSlotNumber())
.assetCode(slotDocument.getAssetCode())
.chamberNumber(slotDocument.getChamberNumber())
.tube(slotDocument.getTube()
.stream()
.map(tubeDocument -> new Tube(tubeDocument.getCode(), tubeDocument.getOffset()))
.toList())
.build();
}
}

View File

@ -0,0 +1,12 @@
package inc.sdt.controlcentermanagement.infrastructure.nosql;
import org.springframework.data.mongodb.repository.MongoRepository;
import java.util.List;
/**
* @author sunae.jang (sa.jang@sdt.inc)
*/
public interface SlotRepository extends MongoRepository<SlotDocument, String> {
List<SlotDocument> findAllByChamberNumber(String chamberNumber);
}

View File

@ -0,0 +1,30 @@
package inc.sdt.controlcentermanagement.infrastructure.nosql;
/**
* @author sunae.jang (sa.jang@sdt.inc)
*/
public class TubeDocument {
private String code;
private String offset;
public TubeDocument(String code, String offset) {
this.code = code;
this.offset = offset;
}
public String getCode() {
return code;
}
public String getOffset() {
return offset;
}
@Override
public String toString() {
return "TubeDocument{" +
"id='" + code + '\'' +
", offset=" + offset +
'}';
}
}

View File

@ -0,0 +1,9 @@
package inc.sdt.controlcentermanagement.infrastructure.resttemplate;
import com.fasterxml.jackson.core.type.TypeReference;
import java.util.Optional;
public interface RestTemplateHandler {
<T> Optional<T> httpPostRequestWithAuth(String url, String authorization, Object body, TypeReference<T> typeReference);
}

View File

@ -0,0 +1,33 @@
package inc.sdt.controlcentermanagement.infrastructure.resttemplate;
import com.fasterxml.jackson.core.type.TypeReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import java.util.Optional;
@Component
public class RestTemplateRequestHandler implements RestTemplateHandler {
private final RestTemplate restTemplate;
private final Logger log;
public RestTemplateRequestHandler(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
this.log = LoggerFactory.getLogger(RestTemplateRequestHandler.class);
}
@Override
public <T> Optional<T> httpPostRequestWithAuth(String url, String authorization, Object body, TypeReference<T> typeReference) {
log.info("[httpPostRequestWithAuth] url = {}", url);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setBearerAuth(authorization.split(" ")[1]);
ParameterizedTypeReference<T> parameterizedType = ParameterizedTypeReference.forType(typeReference.getType());
ResponseEntity<T> response = restTemplate.exchange(url, HttpMethod.POST, new HttpEntity<>(body, headers), parameterizedType);
return Optional.ofNullable(response.getBody());
}
}

View File

@ -0,0 +1,36 @@
package inc.sdt.controlcentermanagement.presentation;
import inc.sdt.controlcentermanagement.application.TubeService;
import inc.sdt.controlcentermanagement.domain.Slot;
import inc.sdt.controlcentermanagement.infrastructure.amqp.ResourceMapping;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
/**
* @author sunae.jang (sa.jang@sdt.inc)
*/
@RestController
public class TubeController {
private final TubeService tubeService;
private final Logger log;
public TubeController(TubeService tubeService) {
this.tubeService = tubeService;
this.log = LoggerFactory.getLogger(TubeController.class);
}
@ResourceMapping(name = "Tube_Control", method = "PATCH", uri = "/chamber/{chamberNumber}/tube/toggle", description = "Tube On/Off 제어")
@ResponseStatus(HttpStatus.OK)
@PatchMapping("/chamber/{chamberNumber}/tube/toggle")
public void toggle(@RequestHeader("Authorization") String authorization, @PathVariable String chamberNumber, @RequestBody Slot slot) {
log.info("[toggle] chamberNumber: {}, slot: {}", chamberNumber, slot);
slot.setChamberNumber(chamberNumber);
if (slot.getTube() != null) {
tubeService.controlByTubeCode(authorization, slot);
} else {
tubeService.controlAll(authorization, slot);
}
}
}

View File

@ -0,0 +1,20 @@
server:
port: ${SERVER_PORT}
spring:
data:
mongodb:
uri: ${MONGODB_URL}
deployer:
endpoint: ${DEPLOYER_ENDPOINT}
iam:
enabled: true
amqp:
host: ${IAM_AMQP_HOST}
port: ${IAM_AMQP_PORT}
username: ${IAM_AMQP_CREDENTIALS_USERNAME}
password: ${IAM_AMQP_CREDENTIALS_PASSWORD}
exchange: iam
routing-key: resource

View File

@ -1 +1,22 @@
server:
port: 8087
spring:
application:
name: control-center-management
data:
mongodb:
uri: mongodb://sdt:251327@localhost:27017/awexomeray?authSource=admin
deployer:
endpoint: http://localhost:8085
iam:
enabled: true
amqp:
host: localhost
port: 5672
username: guest
password: guest
exchange: iam
routing-key: resource

View File

@ -0,0 +1,41 @@
package inc.sdt.controlcentermanagement.infrastructure.nosql;
import inc.sdt.controlcentermanagement.domain.Slot;
import inc.sdt.controlcentermanagement.domain.Tube;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import java.util.List;
/**
* @author sunae.jang (sa.jang@sdt.inc)
*/
@SpringBootTest
@ActiveProfiles("local")
class SlotNoSQLRepositoryTest {
private final Logger log = LoggerFactory.getLogger(this.getClass());
@Autowired
private SlotRepository slotRepository;
@Test
void get() {
List<SlotDocument> findAllByChamberNumber = slotRepository.findAllByChamberNumber("1");
log.info("list: {}", findAllByChamberNumber);
}
private Slot to(SlotDocument slotDocument) {
List<Tube> tube = slotDocument.getTube().stream()
.map(tubeDocument -> new Tube(tubeDocument.getCode(), tubeDocument.getOffset())).toList();
return Slot.builder()
.id(slotDocument.getId())
.slotNumber(slotDocument.getSlotNumber())
.assetCode(slotDocument.getAssetCode())
.chamberNumber(slotDocument.getChamberNumber())
.tube(tube)
.build();
}
}